简体   繁体   English

Delphi FastMM4如何读取MemoryManager_EventLog.txt?

[英]Delphi FastMM4 how read MemoryManager_EventLog.txt?

I have added FastMM4 to my project for detect a memory leak我已将 FastMM4 添加到我的项目中以检测 memory 泄漏

program MyProg;

uses
  {$IFDEF DEBUG}
  FastMM4,
  {$ENDIF}
  ...other uses

on form close FastMM4 produce a MemoryManager_EventLog.txt , with all leak block.在 form close FastMM4 上生成一个MemoryManager_EventLog.txt ,其中包含所有泄漏块。

This is an example:这是一个例子:

    --------------------------------2019/6/19 9:49:25--------------------------------
A memory block has been leaked. The size is: 20

This block was allocated by thread 0x558, and the stack trace (return addresses) at the time was:
4075D2 [System.pas][System][@GetMem$qqri][4614]
40ABAF [System.pas][System][TObject.NewInstance$qqrv][16452]
40B3D6 [System.pas][System][@ClassCreate$qqrpvzc][17790]
40AD20 [System.pas][System][TObject.$bctr$qqrv][16516]
F3BEF6 [NdST.pas][NdST][TFinder.$bctr$qqrp14System.TObject][1011]
11157D1 [SuperNode.pas][SuperNode][TSuperNode.$bctr$qqrp14System.TObject][993]
D1D840 [Network.pas][Network][TNetwork.Create$qqrv][968]
F3A70D [NdST.pas][NdST][TNdST.$bctr$qqrp14System.TObject][177]
F3B658 [NdST.pas][NdST][TNdSTCAP.$bctr$qqrp14System.TObject][652]
10A4CCA [Print.pas][Print][TPrint.CreateCollection$qqrv][4274]
10A2773 [Print.pas][Print][TPrint.CreateItem$qqrv][3031]

The block is currently used for an object of class: TList

The allocation number is: 53883

Current memory dump of 256 bytes starting at pointer address 7EBA5360:
48 FA 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7C C4 2D 79 00 00 00 00 E0 4B BA 7E
00 00 00 00 00 00 00 00 9C CD 41 00 00 00 00 00 7C D2 00 00 D2 75 40 00 AF AB 40 00 D6 B3 40 00
1A 72 11 01 29 AD 40 00 F8 57 11 01 40 D8 D1 00 0D A7 F3 00 58 B6 F3 00 CA 4C 0A 01 73 27 0A 01
58 05 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
20 AD 40 00 B8 AB 40 00 D1 57 11 01 F4 1B 0B 01 22 4D 0A 01 87 27 0A 01 0A 48 11 01 52 6E 11 01
H  ú  I  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |  Ä  -  y  .  .  .  .  à  K  º  ~
.  .  .  .  .  .  .  .  œ  Í  A  .  .  .  .  .  |  Ò  .  .  Ò  u  @  .  ¯  «  @  .  Ö  ³  @  .
.  r  .  .  )  ­  @  .  ø  W  .  .  @  Ø  Ñ  .  .  §  ó  .  X  ¶  ó  .  Ê  L  .  .  s  '  .  .
X  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  x  ï  ï  †
<  -  .  .  À  F  ¼  ~  .  .  .  .  .  .  .  .  .  .  .  .  ‡  .  .  y  .  .  .  .  .  Q  º  ~
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  €  Ò  .  .  Ò  u  @  .  ¯  «  @  .  Ö  ³  @  .
   ­  @  .  ¸  «  @  .  Ñ  W  .  .  ô  .  .  .  "  M  .  .  ‡  '  .  .  .  H  .  .  R  n  .  .

The leak seem to be caused by TList, but I free every TList.泄漏似乎是由 TList 引起的,但我释放了每个 TList。 Is TList.Free not sufficient? TList.Free还不够吗?

So, how to read a FastMM log?那么,如何读取 FastMM 日志呢?

The most relevant section is the one that states "the stack trace (return addresses) at the time was:" where you will see a listing like the one below.最相关的部分是声明“当时的堆栈跟踪(返回地址)是:”的部分,您将在其中看到如下所示的列表。 This is what is called a stack trace.这就是所谓的堆栈跟踪。

A stack trace shows the execution path of your program;堆栈跟踪显示程序的执行路径; which function called which function.哪个 function 调用哪个 function。

First, it is good to know that for each line in the log:首先,很高兴知道对于日志中的每一行:

  • the first number is the memory addres where that function resides (EXE file)第一个数字是 memory 地址,function 所在的地址(EXE 文件)
  • the last number in brackets is the source code line number where the function resides (PAS file).括号中的最后一个数字是 function 所在的源代码行号(PAS 文件)。

We start reading from the bottom.我们从底部开始阅读。

So, we can see that all started in the Print.pas unit.所以,我们可以看到,一切都是从 Print.pas 单元开始的。 The CreateItem method of TPrint object called CreateCollection which tried to create a new object. In the end (see the top lines) we end up in TObject's constructor. TPrint object 的 CreateItem 方法调用了 CreateCollection,它试图创建一个新的 object。最后(见最上面几行)我们在 TObject 的构造函数中结束。 That construnctor is a class method: ClassCreate.该构造函数是一个 class 方法:ClassCreate。 TObject.NewInstance means that the TObject was actually being created. TObject.NewInstance 意味着实际上正在创建 TObject。 There, the constructor allocated (normally) some memory for the TObject via GetMem.在那里,构造函数(通常)通过 GetMem 为 TObject 分配了一些 memory。

Now, until this point, nothing wrong has happened.现在,直到此时,没有发生任何错误。 We allocated some memory when we created an object. Not a big deal.我们在创建 object 时分配了一些 memory。没什么大不了的。 The error happened when the programmer forgot to release that memory back.当程序员忘记释放 memory 时,错误发生了。 In other words, we created an object, and we never freed it.换句话说,我们创建了一个 object,并且我们从未释放过它。

Anyway, the log seems a bit weird because the stack trace shows some items being created.不管怎样,日志看起来有点奇怪,因为堆栈跟踪显示了一些正在创建的项目。
So we need to go into the source code and check all places where we call TPrint.CreateItem.所以我们需要go进入源码,检查所有调用TPrint.CreateItem的地方。 If you have just one place where TPrint.CreateItem is called, you are very lucky.如果您只有一处调用 TPrint.CreateItem 的地方,那您就很幸运了。 You just have to check where that new item SHOULD be released, because it obviously it isn't.您只需要检查应该在哪里发布新项目,因为它显然不是。 If you have just one place where TPrint.CreateItem is called, you are moderatelly lucky.如果您只有一个地方调用了 TPrint.CreateItem,那么您还算幸运。 You have to check EACH place.你必须检查每个地方。


However, then the log complaints that the TList itself is not released (does not complain about its items) - maybe the log is incomplete?然而,然后日志抱怨 TList 本身没有发布(不抱怨它的项目)——也许日志不完整?

The block is currently used for an object of class: TList该块当前用于 class 的 object:TList

So, releasing that TList should be enough.所以,释放那个 TList 应该就足够了。 I guess, what happens here is that some external code takes control over the items and releases them, while TList itself is not released.我想,这里发生的是一些外部代码控制了项目并释放了它们,而 TList 本身没有被释放。


Remember, if you don't see a detailed stack trace, it means that you need to:请记住,如果您没有看到详细的堆栈跟踪,则意味着您需要:

  • disable compiler optimizations禁用编译器优化
  • in the same page, enable stack frames在同一页面中,启用堆栈框架
  • enable map file启用 map 文件

If you create objects and save their references to TList, it is essential that you free them before the TList is freed. 如果创建对象并将其引用保存到TList,则必须在释放TList之前释放它们。

for I := 0 to aList.Count-1 do
   anObjectType(aList[I]).Free;

If you want your objects to be freed automatically, use TObjectList with OwnsObjects parameter set. 如果要自动释放对象,请使用带有OwnsObjects参数集的TObjectList TObjectList frees the memory of all its objects when it is destroyed. TObjectList在销毁时将释放其所有对象的内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM