Несколько лет назад я решил никогда не полагаться только на установку свойства FreeOnTerminate
в true, чтобы быть уверенным в его уничтожении, потому что Я обнаружил и аргументировал две вещи при завершении приложения:
- он вызывает утечку памяти и
- после завершения программы поток по-прежнему работает где-то ниже клавиатуры моего ноутбука.
Я познакомился с обходным решением, и это не беспокоило меня все это время. До сегодняшнего дня, когда снова кто-то (@MartinJames в этом случае) прокомментировал мой ответ, в котором я ссылаюсь на некоторый код, который не использует FreeOnTerminate
в сочетании с преждевременным завершением потока. Я вернулся в RTL-код и понял, что, возможно, сделал неправильные предположения. Но я не совсем уверен в этом, поэтому этот вопрос.
Во-первых, чтобы воспроизвести вышеупомянутые утверждения, этот иллюстративный код используется:
unit Unit3;
interface
uses
Classes, Windows, Messages, Forms;
type
TMyThread = class(TThread)
FForm: TForm;
procedure Progress;
procedure Execute; override;
end;
TMainForm = class(TForm)
procedure FormClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FThread: TMyThread;
end;
implementation
{$R *.dfm}
{ TMyThread }
procedure TMyThread.Execute;
begin
while not Terminated do
begin
Synchronize(Progress);
Sleep(2000);
end;
end;
procedure TMyThread.Progress;
begin
FForm.Caption := FForm.Caption + '.';
end;
{ TMainForm }
procedure TMainForm.FormClick(Sender: TObject);
begin
FThread := TMyThread.Create(True);
FThread.FForm := Self;
FThread.FreeOnTerminate := True;
FThread.Resume;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FThread.Terminate;
end;
end.
Теперь (ситуация A), если вы запустите поток с щелчком по форме и закроете форму сразу после изменения заголовка, происходит утечка памяти из 68 байтов. Я предполагаю, что это потому, что поток не освобожден. Во-вторых, программа немедленно завершается, и среда IDE снова возвращается в нормальное состояние. Это в отличие от (ситуация B): когда не используется FreeOnTerminate
, и последняя строка вышеуказанного кода изменяется на FThread.Free
, она принимает (макс.) 2 секунды от исчезновения программы до нормальной IDE состояние.
Задержка в ситуации B объясняется тем, что FThread.Free
вызывает FThread.WaitFor
, оба из которых выполняются в контексте основного потока. Дальнейшее исследование Classes.pas узнало, что уничтожение потока из-за FreeOnTerminate
выполняется в контексте рабочего потока. Это приводит к следующим вопросам о ситуации A:
- Есть ли утечка памяти? И если да: важно ли это, можно ли его игнорировать? Потому что, когда приложение завершается, Windows не возвращает все зарезервированные ресурсы?
- Что происходит с потоком? Действительно ли он работает где-то в памяти до тех пор, пока его работа не будет выполнена, или нет? И: освобождается ли он, несмотря на доказательства утечки памяти?
Отказ от ответственности: для обнаружения утечки памяти я использую этот очень простой блок как первый в файле проекта.