Введение:
В данной статье рассматривается проблема утечки памяти, возникающая при работе с Server Sent Events (SSE) в среде Delphi 2010 с использованием компонентов Indy10. SSE — это механизм, позволяющий серверу отправлять события клиенту в реальном времени, без необходимости постоянного опроса сервера клиентской частью.
Описание проблемы:
Разработчик столкнулся с проблемой, при которой при закрытии программы, использующей Delphi 2010 и Indy10 для чтения SSE, возникали утечки памяти и на сервере отображалось сообщение о принудительном закрытии соединения. Это происходило из-за некорректного освобождения ресурсов, используемых в потоке для чтения событий.
Пример кода:
В коде, предоставленном разработчиком, используется класс TSSEThread, который создает поток для чтения событий. В методе Execute инициализируются объекты TMemoryStream и TIdHTTP, которые должны быть корректно освобождены при закрытии потока.
constructor TSSEThread.Create(CreateSuspended: Boolean; url: String);
begin
inherited Create(CreateSuspended);
Self.FreeOnTerminate := False;
Self.url := url;
end;
procedure TSSEThread.Execute;
begin
inherited;
try
stream := TMemoryStream.Create;
http_client := TIdHTTP.Create(nil);
// ... инициализация http_client ...
while not Terminated do
begin
try
http_client.Get(self.url,stream);
except
on E: Exception do begin
try
http_client.Disconnect;
except
end;
if http_client.IOHandler <> nil then http_client.IOHandler.InputBuffer.Clear;
sleep(3000);
end;
end;
finally
http_client.Free;
stream.Free;
end;
end;
end;
Подтвержденное решение:
Для корректного закрытия потока и освобождения ресурсов необходимо в обработчике события OnWork использовать исключение SysUtils.Abort при обнаружении, что свойство Terminated истинно. Это приведет к завершению HTTP-запроса и закрытию соединения, после чего исключение будет обработано в методе Execute, где можно проверить Terminated еще раз и освободить ресурсы в блоке finally.
procedure TSSEThread.DoOnWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
if self.Terminated then SysUtils.Abort;
// ... обработка сообщений ...
end;
Альтернативное решение:
В качестве альтернативы, можно настроить свойство ReadTimeout объекта TIdHTTP, чтобы регулярно проверять состояние потока на завершение.
http_client.ReadTimeout := 1000;
Это позволит вызывать обработчик OnWork хотя бы раз в секунду, что может быть достаточным для своевременного обнаружения необходимости закрытия соединения.
Заключение:
При работе с Indy10 и SSE в Delphi 2010 важно обеспечить корректное освобождение ресурсов при закрытии потока. Использование исключений и настройки свойства ReadTimeout позволяют решить проблему утечки памяти и обеспечить более плавное закрытие соединения.
Решение проблемы утечки памяти при использовании компонентов Indy10 и Server Sent Events в среде Delphi 2010.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS