You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GetNamedSecurityInfoW获取文件所有者时出现内存泄漏问题

问题:ctypes调用GetNamedSecurityInfoW导致内存持续增长

我用Python的ctypes调用GetNamedSecurityInfoW获取文件所有者信息,同时用os.walk遍历C盘文件列表。PL_Files.get_fileowner方法能正常返回结果,但每次调用该方法时,进程内存会增加约2MB。就算注释掉LookupAccountSidW函数,内存增长问题依然存在,所以怀疑问题出在GetNamedSecurityInfoW上。我知道如果不使用ppSecurityDescriptor,该函数无需释放内存,但内存还是一直在涨,相关代码如下:

遍历文件代码

for root, dirs, files in os.walk("c:\\"):
    for file in files:
        filename = os.path.join(root, file)
        owner = PL_Files.get_fileowner(filename)
        print(owner)

获取所有者代码

@staticmethod
def get_fileowner(filename):
    dwRet = 0
    pSidOwner = c_void_p()
    ppSecurityDescriptor = c_void_p()
    dwAcctName = DWORD()
    dwDomainName = DWORD()
    peUse = DWORD(SidTypeUnknown)
    
    dwRet = GetNamedSecurityInfoW(filename, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, byref(pSidOwner), None, None, None, None)
    if dwRet != ERROR_SUCCESS:
        return "-1"

    LookupAccountSidW(None, pSidOwner, None, byref(dwAcctName), None, byref(dwDomainName), byref(peUse))
    
    AcctName = create_unicode_buffer(dwAcctName.value + 2)
    DomainName = create_unicode_buffer(dwDomainName.value + 2)
    
    if LookupAccountSidW(None, pSidOwner, AcctName, byref(dwAcctName), DomainName, byref(dwDomainName), byref(peUse)):
        return "{}\\{} ".format(DomainName.value, AcctName.value)
    else:
        return "-1"

函数原型

GetNamedSecurityInfoW = ADVAPI32.GetNamedSecurityInfoW
GetNamedSecurityInfoW.restype = DWORD
GetNamedSecurityInfoW.argtypes = [c_wchar_p, INT, DWORD, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]

问题分析与解决

你误解了内存释放的规则:虽然未使用ppSecurityDescriptor,但GetNamedSecurityInfoW返回的pSidOwner指针指向的SID内存是由系统分配的,必须手动调用LocalFree释放,否则会造成内存泄漏,这就是内存持续增长的原因。

修改后的get_fileowner方法需添加内存释放逻辑:

@staticmethod
def get_fileowner(filename):
    dwRet = 0
    pSidOwner = c_void_p()
    dwAcctName = DWORD()
    dwDomainName = DWORD()
    peUse = DWORD(SidTypeUnknown)
    
    try:
        dwRet = GetNamedSecurityInfoW(filename, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, byref(pSidOwner), None, None, None, None)
        if dwRet != ERROR_SUCCESS:
            return "-1"

        LookupAccountSidW(None, pSidOwner, None, byref(dwAcctName), None, byref(dwDomainName), byref(peUse))
        
        AcctName = create_unicode_buffer(dwAcctName.value + 2)
        DomainName = create_unicode_buffer(dwDomainName.value + 2)
        
        if LookupAccountSidW(None, pSidOwner, AcctName, byref(dwAcctName), DomainName, byref(dwDomainName), byref(peUse)):
            return "{}\\{} ".format(DomainName.value, AcctName.value)
        else:
            return "-1"
    finally:
        # 释放SID占用的内存
        if pSidOwner.value is not None:
            LocalFree(pSidOwner.value)

同时需要导入并定义LocalFree函数:

ADVAPI32 = cdll.LoadLibrary("advapi32.dll")
KERNEL32 = cdll.LoadLibrary("kernel32.dll")
LocalFree = KERNEL32.LocalFree
LocalFree.restype = c_void_p
LocalFree.argtypes = [c_void_p]

另外要确保相关常量已正确定义:

SE_FILE_OBJECT = 1
OWNER_SECURITY_INFORMATION = 0x00000001
ERROR_SUCCESS = 0
SidTypeUnknown = 0

修改后每次调用方法都会释放SID内存,解决内存持续增长的问题。

内容的提问来源于stack exchange,提问作者Saab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:01:33