【发布时间】:2009-06-25 14:19:25
【问题描述】:
我在使用 Delphi 7 中的 WMI 查询(远程)PC 时遇到内存泄漏。内存泄漏仅发生在 Windows 2003(和 Windows XP 64)上。 Windows 2000 很好,Windows 2008 也很好。我想知道是否有人遇到过类似的问题。
泄漏仅发生在某些版本的 Windows 中的事实意味着它可能是 Windows 问题,但我一直在搜索网络,但无法找到解决问题的修补程序。此外,这可能是 Delphi 问题,因为在 C# 中具有类似功能的程序似乎没有这种泄漏。后一个事实使我相信,在 Delphi 中可能有另一种更好的方法来获取我需要的信息,而不会导致内存泄漏。
我已经包含了一个小程序的源代码,以暴露下面的内存泄漏。如果执行{ Leak! } 注释下方的sObject.Path_ 行,就会发生内存泄漏。如果我将其注释掉,则没有泄漏。 (显然,在“真实”程序中,我对sObject.Path_ 方法调用的结果做了一些有用的事情:)。)
通过在我的机器上快速进行 Windows 任务管理器分析,我发现了以下内容:
之前 N=100 N=500 N=1000 带 sObject.Path_ 3.7M 7.9M 18.2M 31.2M 不带 sObject.Path_ 3.7M 5.3M 5.4M 5.3M我想我的问题是:还有其他人遇到过这个问题吗?如果是这样,这确实是 Windows 问题,是否有修补程序?或者(更有可能)我的 Delphi 代码损坏了,有没有更好的方法来获取我需要的信息?
您会注意到有好几次,nil 被分配给对象,这与 Delphi 精神背道而驰……这些 COM 对象不继承自 TObject,并且没有我可以调用的析构函数。通过将nil 分配给它们,Windows 的垃圾收集器会清理它们。
program ConsoleMemoryLeak;
{$APPTYPE CONSOLE}
uses
Variants, ActiveX, WbemScripting_TLB;
const
N = 100;
WMIQuery = 'SELECT * FROM Win32_Process';
Host = 'localhost';
{ Must be empty when scanning localhost }
Username = '';
Password = '';
procedure ProcessObjectSet(WMIObjectSet: ISWbemObjectSet);
var
Enum: IEnumVariant;
tempObj: OleVariant;
Value: Cardinal;
sObject: ISWbemObject;
begin
Enum := (wmiObjectSet._NewEnum) as IEnumVariant;
while (Enum.Next(1, tempObj, Value) = S_OK) do
begin
sObject := IUnknown(tempObj) as SWBemObject;
{ Leak! }
sObject.Path_;
sObject := nil;
tempObj := Unassigned;
end;
Enum := nil;
end;
function ExecuteQuery: ISWbemObjectSet;
var
Locator: ISWbemLocator;
Services: ISWbemServices;
begin
Locator := CoSWbemLocator.Create;
Services := Locator.ConnectServer(Host, 'root\CIMV2',
Username, Password, '', '', 0, nil);
Result := Services.ExecQuery(WMIQuery, 'WQL',
wbemFlagReturnImmediately and wbemFlagForwardOnly, nil);
Services := nil;
Locator := nil;
end;
procedure DoQuery;
var
ObjectSet: ISWbemObjectSet;
begin
CoInitialize(nil);
ObjectSet := ExecuteQuery;
ProcessObjectSet(ObjectSet);
ObjectSet := nil;
CoUninitialize;
end;
var
i: Integer;
begin
WriteLn('Press Enter to start');
ReadLn;
for i := 1 to N do
DoQuery;
WriteLn('Press Enter to end');
ReadLn;
end.
【问题讨论】:
标签: windows delphi com memory-leaks wmi