使用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
相关产品推荐
相关产品推荐

