Thread.FreeOnTerminate:=真,内存泄漏和鬼运行
多年前,我决定永远不要仅仅依靠将线程的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
导致的线程FreeOnTerminate
是在工作线程的上下文中完成的。 这导致关于情况A的以下问题:
免责声明:对于内存泄漏检测,我使用这个非常简单的单元作为项目文件中的第一个单元。
事实上,操作系统在终止时回收所有进程的内存,所以即使这68个字节引用了非释放线程对象,操作系统仍然会将这些字节取回。 在这一点上你是否已经释放了这个对象并不重要。
当你的主程序完成时,它最终会到达一个它调用ExitProcess
的地方。 (您应该能够打开项目链接器选项中的调试DCU,并使用调试器直接跳到那一点。)该API调用会执行几个操作,包括终止所有其他线程。 线程不会被通知他们正在终止,所以TThread
提供的清理代码永远不会运行。 操作系统线程完全不存在。
上一篇: Thread.FreeOnTerminate := True, memory leak and ghost running
下一篇: Effective Java : Making a class as private nested class (Item 22)