Выполняет ли TIdHTTP.Free также очищает назначенный компрессор и IOHandler?

#delphi

#delphi

Вопрос:

У меня есть TIdHTTP объект, созданный во время выполнения, IOHandler Compression свойства которого и установлены для объектов, которые также создаются во время выполнения. Если я вызываю Free свой TIdHTTP объект, автоматически ли это освобождает IOHandler Compression назначенные ему объекты and ?

 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;
 

Приведет ли это к утечке памяти компрессора и IOHandler или они будут автоматически уничтожены?

На всякий случай, если он не будет автоматически уничтожен, я добавил переопределение для такого Destroy метода:

 destructor TIdHTTP.Destroy;
begin
  if Assigned(Compressor) then
    Compressor.Free;
  if Assigned(IOHandler) then
    IOHandler.Free;

  inherited;
end;
 

Ответ №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;
 

Вы также хотите выполнить надлежащую обработку исключений, но я предполагаю, что вы оставили это для краткости.

Наконец, если вы сомневаетесь в утечках памяти, использование встроенного FastMM в FullDebugMode сообщит и зарегистрирует все утечки памяти при завершении работы. Это помогло бы вам обнаружить утечку памяти в данном случае, но в целом рекомендуется также выявлять утечки, о которых вы еще не подумали 😉

Комментарии:

1. Спасибо за подробное объяснение. Я загляну в FastMM. Я использую обработку исключений в реальном коде, я просто урезал его до тех частей, которые, по моему мнению, имеют непосредственное отношение.

2. Кстати, вам не нужно создавать SSLlOHandler, если вы не обращаетесь к URL-адресам HTTPS (чего в вашем примере нет). И если вы это делаете и используете обновленную версию Indy, вам не нужно создавать SSLIOHandler, если вам не нужно настраивать его параметры.