在动态包中使用TTask会导致调试器中的内存泄漏和访问冲突。在某些情况下,似乎TTask不适合在动态打包应用程序中使用。
我在delphi包中定义了一个外部过程:
unit LibUnit;
interface
implementation
uses System.Threading, Winapi.Windows;
procedure Test;
begin
TTask.Run(procedure begin OutputDebugString(PChar('Task Executing')); end);
end;
exports Test;
end.
然后我在我的主应用程序中使用该过程:
uses
System.SysUtils,
System.Threading,
Winapi.Windows;
var H: THandle;
P: procedure;
begin
ReportMemoryLeaksOnShutdown := True;
H := LoadPackage('MyPackage.bpl');
@P := GetProcAddress(H, PChar('Test'));
P;
Sleep(1000);
OutputDebugString(PChar('Start unload package'));
UnloadPackage(H);
ReadLn;
end.
应用程序关闭后提示内存泄漏:
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):
13 - 20 bytes: Unknown x 1
21 - 36 bytes: TThreadPool.TControlFlag x 1
69 - 84 bytes: TTask x 1
示例项目可以从RSP-15316
下载我注意到这是由于在卸载软件包后在TTask exit中创建的新线程:
Thread Start: Thread ID: 8308. Process MainProject.exe (6208)
Debug Output: Task Executing Process MainProject.exe (6208)
Debug Output: Start unload package Process MainProject.exe (6208)
Module Unload: MyPackage.bpl. Process MainProject.exe (6208)
Debug Output: Thread Exiting: 8308 Process MainProject.exe (6208) message 'access violation at 0x50067528: read of address 0x02351fb8'. Process MainProject.exe (6208)
Thread Exit: Thread ID: 8308. Process MainProject.exe (6208)
如果我们可以在线程退出后找到控制包卸载的方法,那么内存泄漏就不会再发生了。
答案 0 :(得分:0)
我找到了一种解决方法。不要使用ThreadPool类本身管理的默认TThreadPool实例。相反,定义自己的TThreadPool实例并在TTask中使用:
unit LibUnit;
interface
implementation
uses System.Threading, Winapi.Windows;
var ThreadPool: TThreadPool;
procedure Test;
begin
TTask.Run(procedure begin OutputDebugString(PChar('Task Executing')); end, ThreadPool);
end;
exports Test;
initialization
ThreadPool := TThreadPool.Create;
finalization
ThreadPool.DisposeOf;
end.