【问题标题】:Does TIdHTTP.Free also clean up assigned Compressor and IOHandler?TIdHTTP.Free 是否也清理分配的 Compressor 和 IOHandler?
【发布时间】:2016-10-16 14:07:25
【问题描述】:

我有一个在运行时创建的TIdHTTP 对象,它的IOHandlerCompression 属性设置为也在运行时创建的对象。如果我在我的TIdHTTP 对象上调用Free,这会自动释放分配给它的IOHandlerCompression 对象吗?

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;

【问题讨论】:

    标签: delphi


    【解决方案1】:

    对象的生命周期与其所有者的生命周期相关;如果一个对象被释放,它将释放它的所有子对象。如果您在创建对象时未传递所有者,则您有责任在不再需要该对象时自行释放该对象。

    这意味着在您的具体示例中,Compressor 将与客户端一起释放(因为您将 TIdHttp 实例作为所有者传递),而 IOHandler 将被泄露(因为您将 nil 作为所有者传递,并且不要自己释放它)。将 Result 作为所有者传递给两者将使您的析构函数过时。此外,不要养成“以防万一”编写代码的习惯。行为是确定性的,所以如果你不知道这是一种方式还是另一种方式,你应该努力找出来,而不是仅仅为两者做计划;)

    您展示的代码有更大的潜在内存泄漏:如果在Get-Request 期间引发异常,则TIdHttp 实例本身将被泄漏(与Compressor 一起)。事实上,如果您按原样运行代码,确实会发生这种情况,因为 Google 会发出重定向,而客户端未设置为处理此重定向。您应该像这样将代码包装在try-finally 中:

    with CreateHTTP do begin
      try
        Get('http://google.com');
      finally
        Free;
      end;
    end;
    

    您还想进行适当的异常处理,但为了简洁起见,我假设您忽略了这一点。

    最后,当对内存泄漏有疑问时,在 FullDebugMode 中使用内置 FastMM 将在关机时报告并记录所有内存泄漏。这将有助于您在这种情况下发现内存泄漏,但通常建议您也发现您尚未考虑过的泄漏;)

    【讨论】:

    • 感谢详细的解释。我将研究 FastMM。我确实在实际代码中使用了异常处理,我只是将其精简到我认为立即相关的部分。
    • 附带说明,除非您正在访问 HTTPS url(您的示例不是),否则您不需要创建 SSLlOHandler。如果您这样做,并且正在使用最新版本的 Indy,you don't need to create the SSLIOHandler,除非您需要自定义其设置。
    猜你喜欢
    • 2010-10-15
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 2012-06-24
    • 2013-05-28
    • 2011-05-07
    相关资源
    最近更新 更多