Thread.FreeOnTerminate := True,内存泄漏和幽灵运行 [英] Thread.FreeOnTerminate := True, memory leak and ghost running
问题描述
多年前,我决定不再仅仅依赖于设置线程的FreeOnTerminate
属性为 true 以确保其销毁,因为我在应用程序终止时发现并推理了两件事:
Years ago, I decided never to rely solely on setting a thread's FreeOnTerminate
property to true to be sure of its destruction, because I discovered and reasoned two things at application's termination:
- 它会导致内存泄漏,并且
- 程序终止后,该线程仍在我笔记本键盘下方的某处运行.
我熟悉了一种解决方法,并且一直没有打扰我.直到今晚,当再次有人(在本例中为 @MartinJames)对我的答案发表评论时,我在其中引用了一些代码不要将 FreeOnTerminate
与线程的提前终止结合使用.我回到 RTL 代码并意识到我可能做出了错误的假设.但我也不太确定,因此这个问题.
I familiarized myself with a workaround, and it did not bother me all this time. Until tonight, when again someone (@MartinJames in this case) commented on my answer in which I refer to some code that does not use FreeOnTerminate
in combination with premature termination of the thread. I dove back in the RTL code and realized I may have made the wrong assumptions. But I am not quite sure about that either, hence this question.
首先,为了重现上述语句,使用了以下说明性代码:
First, to reproduce the above mentioned statements, this illustrative code is used:
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秒.
Now (situation A), if you start the thread with a click on the form, and close the form right after the caption changed, there is a memory leak of 68 bytes. I assume this is because the thread is not freed. Secondly, the program terminates immediately, and the IDE is at that same moment back again in normal state. That in contrast to (situation B): when not making use of FreeOnTerminate
and the last line of the above code is changed into FThread.Free
, it takes (max.) 2 seconds from the disappearance of the program to the normal IDE state.
情况 B 中的延迟是由 FThread.Free
调用 FThread.WaitFor
的事实来解释的,这两者都在主线程的上下文中执行.对 Classes.pas 的进一步调查了解到,由于 FreeOnTerminate
导致的线程销毁是在工作线程的上下文中完成的.这导致以下关于情况 A 的问题:
The delay in situation B is explained by the fact that FThread.Free
calls FThread.WaitFor
, both which are executed in the context of the main thread. Further investigation of Classes.pas learned that the destruction of the thread due to FreeOnTerminate
is done in the context of the worker thread. This lead to the following questions on situation A:
- 确实存在内存泄漏吗?如果是这样:它很重要,可以忽略吗?因为当应用程序终止时,Windows 不会归还所有保留的资源吗?
- 线程会发生什么?在它的工作完成之前,它是否确实在内存中的某个地方运行得更远?并且:它是否被释放,尽管有内存泄漏的证据?
免责声明:对于内存泄漏检测,我使用这个非常简单的单元 作为项目文件中的第一个.
Disclaimer: For memory leak detection, I use this very simple unit as first in the project file.
推荐答案
确实,操作系统会在进程终止时回收进程的所有内存,因此即使这 68 个字节指向未释放的线程对象,操作系统也会无论如何取回这些字节.那个时候你是否释放了对象并不重要.
Indeed, the OS reclaims all a process's memory when it terminates, so even if those 68 bytes refer to the non-freed thread object, the OS is going to take those bytes back anyway. It doesn't really matter whether you've freed the object at that point.
当您的主程序完成时,它最终会到达一个调用 退出进程
.(您应该能够在项目的链接器选项中打开调试 DCU,并使用调试器逐步执行到该点.)该 API 调用执行多项操作,包括终止所有其他线程.线程不会被通知它们正在终止,因此 TThread
提供的清理代码永远不会运行.操作系统线程不复存在.
When your main program finishes, it eventually reaches a place where it calls ExitProcess
. (You should be able to turn on debug DCUs in your project's linker options and step through to that point with the debugger.) That API call does several things, including terminating all other threads. The threads are not notified that they're terminating, so the cleanup code provided by TThread
never runs. The OS thread simply ceases to exist.
这篇关于Thread.FreeOnTerminate := True,内存泄漏和幽灵运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!