Postanowiłem nigdy nie polegać wyłącznie na ustawianiu właściwości wątku na FreeOnTerminate
, aby być pewnym jej zniszczenia, ponieważ odkryłem i uzasadniłem dwie rzeczy na zakończenie aplikacji:Thread.FreeOnTerminate: = Prawda, przeciek pamięci i upiory
- produkuje przeciek pamięci, a
- po zakończeniu programu, nitka wciąż działa gdzieś poniżej klawiaturze moim notebooku.
Zapoznałem się z obejściem problemu i nie przeszkadzało mi to przez cały ten czas. Aż do dzisiaj, kiedy znowu ktoś (@MartinJames w tym przypadku) skomentował na my answer, w którym odwołuję się do kodu, który nie używa FreeOnTerminate
w połączeniu z przedwczesnym zakończeniem wątku. Wróciłem do kodu RTL i zdałem sobie sprawę, że mogłem popełnić złe założenia. Ale nie jestem do końca tego pewien, stąd to pytanie.
Po pierwsze, aby odtworzyć powyższe wypowiedzi, używany jest ten kod ilustracyjne:
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.
Now (sytuacja A), jeśli zaczniesz nić za pomocą kliknięcia na formularzu, a następnie zamknij formularz tuż po podpis zmienił się, istnieje wyciek pamięci o długości 68 bajtów. Zakładam, że dzieje się tak, ponieważ wątek nie został uwolniony. Po drugie, program kończy się natychmiast, a IDE jest w tej samej chwili z powrotem w normalnym stanie. W przeciwieństwie do (sytuacja B): gdy nie używasz FreeOnTerminate
, a ostatnia linia powyższego kodu zmienia się na FThread.Free
, trwa (maksymalnie) 2 sekundy od zniknięcia programu do normalnego stanu IDE.
Opóźnienie w sytuacji B tłumaczy się tym, że FThread.Free
dzwoni FThread.WaitFor
, oba są wykonywane w kontekście głównego wątku. Dalsze badania Classes.pas dowiodły, że zniszczenie wątku z powodu FreeOnTerminate
odbywa się w kontekście wątku roboczego. To prowadzi do następujących pytań na temat sytuacji:
- Czy rzeczywiście występuje wyciek pamięci? A jeśli tak, to czy jest to ważne, czy można go zignorować? Ponieważ po zamknięciu aplikacji system Windows nie zwraca wszystkich zarezerwowanych zasobów?
- Co dzieje się z nitką? Czy rzeczywiście biegnie gdzieś w pamięci, dopóki jej praca nie zostanie zakończona, czy nie? I: czy jest uwolniony, pomimo dowodów wycieku pamięci?
Nota prawna: W przypadku wykrywania nieszczelności pamięci używam this very simple unit jako pierwszego w pliku projektu.
Nie wiem, czy już czytałeś, ale uważam, że bardzo przydatne są posty z [Raymond Chen] (http: //blogs.msdn.com/b/oldnewthing) na temat tego rodzaju tematów. Weź to [jeden jako przykład] (http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx) lub [dwa] (http://blogs.msdn.com/ b/oldnewthing/archive/2007/05/02/2365433.aspx # 2375204). Zobacz także komentarze i połączone posty. – EMBarbosa