2

为了消除所有内存泄漏,我试图将LeakCheck库合并到 DUnit 中。问题是 LeakCheck 会向我报告不是真正泄漏的内存泄漏。这些是由 RTL 分配并在程序退出时销毁的对象或其他东西。

LeakCheck 包含许多允许您指定要忽略的例程,我能够使用它们来忽略大多数此类“泄漏”。但是,我不知道如何特别摆脱一个:

program LeakCheckMemLeak;
{$APPTYPE CONSOLE}
uses
  LeakCheck, TestFramework, LeakCheck.DUnit, LeakCheck.Utils,  LeakCheck.Setup.Trace, System.SysUtils,
  Forms, System.Classes;

{$R *.RES}

procedure LeakMemory;
var
  LThread: TThread;
begin
  LThread := TThread.Create(True);
  LThread.Free;
end;

procedure DetectLeak;
var
  Snapshot: TLeakCheck.TSnapshot;
  Report: LeakString;
begin
  Snapshot.Create;
  LeakMemory;
  Report := TLeakCheck.GetReport(Snapshot.Snapshot);
  try
    Writeln(string(Report));
  finally
    Report.Free;
  end;
end;

begin
  Application.Initialize;
  DetectLeak;
  Readln;
end.

创建实例TThread(最初是,TThread.CreateAnonymousThread但结果相同)会导致 64 字节的内存泄漏:

Total allocation count: 297 (12592 B)
Leak detected 02BB3DC0 size 64 B
  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E8 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ????????????????????????????????
  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ????????????????????????????????
Stack trace when the memory block was allocated:
  $00406E76 - LeakCheckMemLeak.exe - System.AllocMem + $A (4562 +25)
  $004C4A53 - LeakCheckMemLeak.exe - System.Classes.TThread.WaitFor + $8F (15565 +23)
  $005E4EB0 - LeakCheckMemLeak.exe - LeakCheckMemLeak.DetectLeak + $34 (24 +3)
  $005ED5B9 - LeakCheckMemLeak.exe - LeakCheckMemLeak.LeakCheckMemLeak + $29 (35 +3)
  $763E343D - kernel32.dll
  $76F19832 - ntdll.dll

在其他情况下,LeakCheck 为我提供了该实例泄漏的类的名称,因此我可以将其添加到忽略列表中,但在这种情况下它没有。我怎样才能抑制这种“泄漏”?

附带说明一下,我遇到的这个和其他泄漏不会发生在 GUI 应用程序中。我猜,RTL 在测试运行之前会为这些对象中的大多数预先分配内存。

4

1 回答 1

2

FWIW 删除 Forms 和 Application.Initialize 后得到的结果是这样的:

Total allocation count: 113 (4152 B)
Leak detected 0262F540 size 44 B for class: TExternalThread
Leak detected 0260A988 size 20 B for class: TThreadList<System.Classes.TThread>
Leak detected 02618A90 size 8 B for class: TObject
Leak detected 026451F8 size 52 B for class: TList<System.Classes.TThread>
Leak detected 02618AC8 size 12 B
  01 00 00 00 01 00 00 00 40 F5 62 02 | ????????@?b?

我通过在 Spring4D 单元测试中使用 LeakCheck 知道,这来自一些实例的延迟初始化,这些实例在TThread.GetCurrentThread您的LeakMemory例程中被调用 - 更准确地说是在TThread.Destroy调用期间WaitFor(参见System.Classes.pasDelphi 10.2.3 中的第 15764 行)。这将创建您在我发布的报告中看到的实例。

我们在 Spring4D 和工作测试中所做的是在运行任何测试之前调用我们知道会导致实例延迟初始化的各种方法和例程(TEncoding例如,另一个候选对象)。这可以防止在测试运行期间的延迟初始化,然后在测试之前和之后在内存增量中体现出来。见InitializeLeakCheck_Spring.TestRunner.pas

虽然您可以将 LeakCheck 配置为忽略这些泄漏,但它会显着影响性能,因为它会从一开始就发现泄漏。如果这些实例在更改之前被初始化,那么以后就没有什么可忽略的了。

于 2018-07-18T14:23:20.843 回答