内存泄漏在Win64 Delphi RTL在线程关闭?
长期以来,我注意到我的服务器应用程序的Win64版本泄漏内存。虽然Win32版本工作正常与相对稳定的内存占用,64位版本使用的内存增加定期 – 也许20Mb /天,没有任何明显的原因(不用说,FastMM4没有报告任何内存泄漏的两个) 。源代码在32位和64位版本之间是相同的。该应用程序是围绕Indy TIdTCPServer组件构建的,它是一个高度多线程的服务器,连接到处理由Delphi XE2生成的其他客户端发送的命令的数据库。
我花了很多时间审查自己的代码,并试图了解为什么64位版本泄漏了这么多的内存。我最终通过使用MS工具设计来跟踪内存泄漏,如DebugDiag和XPerf,似乎有一个根本的缺陷在Delphi 64bit RTL,导致一些字节被泄漏每次一个线程已从DLL分离。这个问题对于必须每天24小时运行而不重新启动的高度多线程应用程序特别重要。 我复制了一个非常基本的项目,由主机应用程序和库组成的两个用XE2构建的问题。 DLL与主机应用程序静态链接。主机应用程序创建的线程只是调用虚拟导出过程并退出: 这里是库的源代码: library FooBarDLL; uses Windows,System.SysUtils,System.Classes; {$R *.res} function FooBarProc(): Boolean; stdcall; begin Result := True; //Do nothing. end; exports FooBarProc; 主机应用程序使用一个计时器来创建一个只调用导出过程的线程: TFooThread = class (TThread) protected procedure Execute; override; public constructor Create; end; ... function FooBarProc(): Boolean; stdcall; external 'FooBarDll.dll'; implementation {$R *.dfm} procedure THostAppForm.TimerTimer(Sender: TObject); begin with TFooThread.Create() do Start; end; { TFooThread } constructor TFooThread.Create; begin inherited Create(True); FreeOnTerminate := True; end; procedure TFooThread.Execute; begin /// Call the exported procedure. FooBarProc(); end; 下面是一些屏幕截图,显示使用VMMap的泄漏(看看红线命名为“堆”)。在30分钟间隔内拍摄以下截图。 32位二进制表示增加了16个字节,这是完全可以接受的: 64位二进制表示增加12476字节(从820K到13296K),这是更有问题: 堆内存的不断增加也由XPerf证实: 使用DebugDiag我能够看到分配泄漏内存的代码路径: LeakTrack+13529 <my dll>!Sysinit::AllocTlsBuffer+13 <my dll>!Sysinit::InitThreadTLS+2b <my dll>!Sysinit::::GetTls+22 <my dll>!System::AllocateRaiseFrame+e <my dll>!System::DelphiExceptionHandler+342 ntdll!RtlpExecuteHandlerForException+d ntdll!RtlDispatchException+45a ntdll!KiUserExceptionDispatch+2e KERNELBASE!RaiseException+39 <my dll>!System::::RaiseAtExcept+106 <my dll>!System::::RaiseExcept+1c <my dll>!System::ExitDll+3e <my dll>!System::::Halt0+54 <my dll>!System::::StartLib+123 <my dll>!Sysinit::::InitLib+92 <my dll>!Smart::initialization+38 ntdll!LdrShutdownThread+155 ntdll!RtlExitUserThread+38 <my application>!System::EndThread+20 <my application>!System::Classes::ThreadProc+9a <my application>!SystemThreadWrapper+36 kernel32!BaseThreadInitThunk+d ntdll!RtlUserThreadStart+1d 雷米Lebeau helped me on the Embarcadero forums了解发生了什么:
看起来很清楚,我有一个重大缺陷在Win64的方式来处理线程关闭。这种行为禁止开发任何必须在Win64下运行27/7的多线程服务器应用程序。 所以: >你对我的结论有什么看法? 测试源代码和二进制代码can be downloaded here。 感谢您的贡献! 编辑:QC Report 105559.我在等你的投票:-) 解决方法
一个非常简单的工作是重新使用线程,而不是创建和销毁它们。线程是相当昂贵,你可能会得到一个perf提升太…调试虽然… …
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |