Thread.FreeOnTerminate := True, утечка памяти и запуск призрака

Много лет назад я решил никогда не полагаться только на установку свойства FreeOnTerminate потока в true, чтобы быть уверенным в его уничтожении, потому что я обнаружил и обосновал две вещи при завершении приложения:

  1. это приводит к утечке памяти, и
  2. после завершения программы поток все еще работает где-то под клавиатурой моего ноутбука.

Я ознакомился с обходным решением, и все это время оно меня не беспокоило. До сегодняшнего вечера, когда снова кто-то (в данном случае @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 не возвращает все зарезервированные ресурсы?
  • Что происходит с потоком? Действительно ли он продолжает выполняться где-то в памяти до тех пор, пока его работа не будет завершена, или нет? И: освобождается ли он, несмотря на доказательства утечки памяти?

Отказ от ответственности: Для обнаружения утечки памяти я использую этот очень простой блок, как первый в файле проекта.

13
задан Community 23 May 2017 в 12:14
поделиться

0 ответов

Другие вопросы по тегам:

Похожие вопросы: