Thread.FreeOnTerminate:= True,内存泄漏和ghost运行 [英] Thread.FreeOnTerminate := True, memory leak and ghost running

查看:188
本文介绍了Thread.FreeOnTerminate:= True,内存泄漏和ghost运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几年前,我决定不要仅仅依靠设置线程的 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:


  1. 它会导致内存泄漏,并且程序终止后

  2. ,该线程仍然运行在笔记本电脑键盘下方。

我熟悉了一个解决方法,并没有打扰我所有这一次。直到今天晚上,当再次有人(@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.

当你的主程序完成后,它最终到达一个调用 ExitProcess 。 (您应该可以在项目的链接器选项中打开调试DCU,并且通过调试器逐步完成这一点。)该API调用包括终止所有其他线程。线程不会被通知它们正在终止,所以由 TThread 提供的清理代码永远不会运行。 OS线程不再存在。

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,内存泄漏和ghost运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆