#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, если вам не нужно настраивать его параметры.