Delphi xe5 使用TIdHTTP和TIdSSLIOHandlerSocketOpenSSL的内存泄漏

Delphi xe5 使用TIdHTTP和TIdSSLIOHandlerSocketOpenSSL的内存泄漏,delphi-xe5,indy10,Delphi Xe5,Indy10,我有以下课程 type TMyDownload = class private FHttp: TIdHttp; function VerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean; public constructor Create(const ARootCertFile: string); destructor Destroy; overr

我有以下课程

type
  TMyDownload = class
  private
    FHttp: TIdHttp;
    function VerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean;
  public
    constructor Create(const ARootCertFile: string);
    destructor Destroy; override;
    function Get(const URL: string; Stream: TStream): Integer;
  end;

constructor TMyDownload.Create(const ARootCertFile: string);
begin
  inherited Create;

  FHttp := TIdHTTP.Create;
  FHttp.Compressor := TIdCompressorZLib.Create(FHttp);
  FHttp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(FHttp);
  FHttp.HandleRedirects := True;
  FHttp.ProtocolVersion := pv1_1;
  FHttp.ConnectTimeout := 10000;
  FHttp.ReadTimeout := 10000;
  FHttp.AllowCookies := True;

  with TIdSSLIOHandlerSocketOpenSSL(FHttp.IOHandler) do
  begin
    OnVerifyPeer := VerifyPeer;
    SSLOptions.Mode := sslmClient;
    SSLOptions.Method := sslvTLSv1_2;
    SSLOptions.RootCertFile := ARootCertFile;
    SSLOptions.SSLVersions := [sslvTLSv1_2];
    SSLOptions.VerifyMode := [sslvrfPeer, sslvrfFailIfNoPeerCert, sslvrfClientOnce];
    SSLOptions.VerifyDepth := 5;
  end;
end;

destructor TMyDownload.Destroy;
begin
  FreeAndNil(FHttp);
  inherited;
end;

function TMyDownload.Get(const URL: string; Stream: TStream): Integer;
begin
  try
    FHttp.Get(URL, Stream, [304]);
    Exit(FHttp.ResponseCode);
  except
    LogException(ClassName, False, True);
    Result := 500;
  end;
end;

function TMyDownload.VerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean;
var
  CurrentTime: TDateTime;
begin
  if (ADepth = 0) then
  begin
    if AOk and (AError = 0) then
    begin
      CurrentTime := Now;
      Result := (Pos('/CN=' + UpperCase(FHttp.URL.Host) + '/', '/' + UpperCase(Certificate.Subject.OneLine) + '/') <> 0)
                and (CurrentTime >= Certificate.notBefore)
                and (CurrentTime <= Certificate.notAfter);
    end
    else
      Result := False;
  end
  else
    Result := AOk and (AError = 0);
end;
上述代码构成了整个程序。如果运行3到5天,程序将耗尽内存(在Win32上消耗2+GB)。如果我禁用

SSLOptions.RootCertFile := ARootCertFile;
该程序运行良好,但缺点是必须接受不安全的链证书


是否有我遗漏的东西,有没有人能给我指出正确的方向

我看不到这段代码中有任何会导致泄漏的东西。您是否使用Delphi的
ReportMemoryLeaksOnShutdown
检查是否报告了真正的泄漏?也许您正在经历内存碎片而不是泄漏?如果没有关于应用程序内存使用的更多信息,真的很难区分这种或那种方式。在旁注中,如果引发了
EIdHTTPProtocolException
,您的
Get()
方法应该返回
FHttp.ResponseCode
。相信我,它确实泄漏了。如果禁用“SSLOptions.RootCertFile”行,它不会泄漏。重申一下,代码代表了整个程序,仅仅因为内存使用量随着时间的推移而增加并不一定意味着内存正在泄漏。碎片内存不是泄漏内存。你需要更深入地调试你的应用程序,以找出实际情况。你显示的不是全部代码,因为你没有显示每1分钟调用
TMyDownload.Get()
的实际循环。但我刚刚做了一个测试,使用Indy 10的最新SVN版本和来自的最新OpenSSL 1.0.2o DLL,并完全按照您显示的方式运行代码(包括证书的使用),每500毫秒循环一次下载,内存使用在几分钟内保持稳定。因此,你的应用程序中的其他东西可能会泄漏/碎片内存,而你只是将其归因于Indy。
SSLOptions.RootCertFile := ARootCertFile;