我在运行时创建了一个TIdHTTP
对象,其IOHandler
和Compression
属性设置为在运行时也创建的对象。如果我在Free
对象上拨打TIdHTTP
,是否会自动释放分配给它的IOHandler
和Compression
个对象?
function CreateHTTP():TIdHTTP;
begin
Result := TIdHTTP.Create(nil);
Result.Compressor := TIdCompressorZLib.Create(Result)
Result.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
end;
在应用程序的其他地方,这个代码被多次调用:
with CreateHTTP() do begin
Data := Get('http://google.com');
Free;
end;
这会导致Compressor和IOHandler的内存泄漏,还是会自动销毁?
万一它没有被自动销毁,我为Destroy
方法添加了一个覆盖:
destructor TIdHTTP.Destroy;
begin
if Assigned(Compressor) then
Compressor.Free;
if Assigned(IOHandler) then
IOHandler.Free;
inherited;
end;
答案 0 :(得分:5)
对象的生命周期与其拥有者的生命周期有关;如果一个对象被释放,它将释放所有的孩子。如果您在创建对象时未传递所有者,则您有责任在不再需要该对象时自行释放该对象。
这意味着在您的特定示例中,Compressor
将被客户端释放(因为您将TIdHttp
实例作为所有者传递),而IOHandler
将被泄露(因为你作为所有者传递零,并且不要自己释放)。将Result
作为所有者传递给两者将使您的析构函数过时。此外,不要养成“以防万一”编写代码的习惯。这种行为是确定性的,所以如果你不知道它是否应该以某种方式找到答案,而不仅仅是计划两者;)
您展示的代码具有更大的潜在内存泄漏:如果在Get
- 请求期间引发异常,则TIdHttp
实例本身将被泄露(以及Compressor
)。事实上,如果您按原样运行代码会发生这种情况,因为Google会发出重定向,并且客户端未设置为处理此重定向。您应该将代码包装在try-finally
中,如下所示:
with CreateHTTP do begin
try
Get('http://google.com');
finally
Free;
end;
end;
你也想做适当的异常处理,但我假设你为了简洁而把它留了下来。
最后,如果对内存泄漏有疑问,使用FullDebugMode中的内置FastMM将报告并记录关闭时的所有内存泄漏。这可以帮助你发现这个实例中的内存泄漏,但一般建议也要发现你还没有想到的泄漏;)