Несколько лет назад я решил никогда не полагаться исключительно на установку свойства 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
, от исчезновения программы до нормальной IDE требуется (максимум) 2 секунды состояние.
Задержка в ситуации B объясняется тем, что FThread.Free
вызывает FThread.WaitFor
, оба из которых выполняются в контексте основного потока. Дальнейшее изучение Classes.pas показало, что уничтожение потока из-за FreeOnTerminate
выполняется в контексте рабочего потока. Это приводит к следующим вопросам о ситуации A:
- Действительно ли есть утечка памяти? И если так: важно ли это, можно ли его игнорировать? Потому что, когда приложение завершает работу, Windows не возвращает все свои зарезервированные ресурсы?
- Что происходит с потоком? Действительно ли он движется дальше где-то в памяти, пока его работа не будет выполнена, или нет? И: освобожден ли он, несмотря на признаки утечки памяти?
Отказ от ответственности: для обнаружения утечки памяти я использую это очень простое устройство в качестве первого в файле проекта.