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的以下问题:

  • 是否确实存在内存泄漏? 如果是这样:是否重要,是否可以忽略? 因为当一个应用程序终止时,Windows不会将其所有保留的资源归还?
  • 线程会发生什么? 它是否真的在内存中的某个地方继续运行,直到它的工作完成或者没有完成? 而且:尽管有内存泄漏的证据,它是否被释放?
  • 免责声明:对于内存泄漏检测,我使用这个非常简单的单元作为项目文件中的第一个单元。


    事实上,操作系统在终止时回收所有进程的内存,所以即使这68个字节引用了非释放线程对象,操作系统仍然会将这些字节取回。 在这一点上你是否已经释放了这个对象并不重要。

    当你的主程序完成时,它最终会到达一个它调用ExitProcess的地方。 (您应该能够打开项目链接器选项中的调试DCU,并使用调试器直接跳到那一点。)该API调用会执行几个操作,包括终止所有其他线程。 线程不会被通知他们正在终止,所以TThread提供的清理代码永远不会运行。 操作系统线程完全不存在。

    链接地址: http://www.djcxy.com/p/92027.html

    上一篇: Thread.FreeOnTerminate := True, memory leak and ghost running

    下一篇: Effective Java : Making a class as private nested class (Item 22)