FastMM4说“块头已被破坏”

时间:2009-07-09 20:47:37

标签: delphi delphi-7 fastmm memory-corruption

我有这个令人讨厌的错误,它在过去消失了,但现在经过一段时间它又回来了。

我有两个TSam对象(从TPersistent派生)创建并加载到TAsmJob对象(从TObjectList派生)。

在运行时,表单创建一个TStringGrid,然后创建AsmJob,它创建这两个SAM对象(并从每个对象的磁盘加载一些数据)。 AsmJob也被分配给网格。 当表单被销毁时,Grid通过释放它来处理AsmJob,从而释放TSam对象。这是问题所在:第一个对象没有问题,但第二个对象在调用其继承的方法(在Destroy析构函数中)时会死掉。

我在整个程序中使用FreeAndNil来释放对象。 TSam对象不是NIL !!!!!所以,这是第一次释放对象的尝试。甚至对象内部的数据也是一致的。

该计划的主干如下:

**Create:**

Form -> StringGrid
     -> AsmJob -> Sam1, Sam2
StringGrid.AsmJob:= AsmJob;


**Free:**

Form -> StringGrid -> AsmJob -> Sam1, Sam2

我真的不明白我试图在它被释放后双重释放或覆盖它的位置。


编辑:

我得到的一些错误:

  • FastMM在a期间检测到错误 自由块扫描操作。 FastMM 检测到一个块已经存在 被释放后修改。

  • FastMM在a期间检测到错误 自由块扫描操作。块 标题已损坏。

详情:

The current thread ID is 0x19C, and the stack trace (return addresses) leading to this error is: 
402E77 [System][@FreeMem] 
4068DC [System][@DynArrayClear] 
405E2D [System][@FinalizeArray] 
405D31 [System][@FinalizeRecord] 
40432F [System][TObject.CleanupInstance] 
404272 [System][TObject.FreeInstance] 
404641 [System][@ClassDestroy] 
4D313E [UnitSam.pas][TSam.Destroy][297] 
4042BF [System][TObject.Free] 
4149ED [SysUtils][FreeAndNil] 
4D9C0A [UnitAsmJob.pas][UnitAsmJob][TAsmJob.Destroy][180]  

我在IDE中启用了所有“调试”选项,包括“范围检查”。此外,FastMM4设置为超级激进的调试模式。如果没有FastMM或者在调试器之外,程序运行得很好 - 但我知道这并不意味着错误不再存在。实际上它(可能)工作了一年多,直到我安装了FastMM。


编辑:

感谢大家。不,我感觉我正朝着好的方向前进。

程序的结构更复杂我只提供了保持原始帖子小的骨干。但到底是什么,它已经变大了:) 因此,那些TSam对象用于从磁盘加载数据。每个对象中有一个文件。他们还在进行一些处理和数据验证。对于这些TSam中的每一个,我还有一个图形对象,在屏幕上(图形地)显示TSam对象中包含的数据。 TStringGrid中的每一行也以TSam显示数据,但是以文本方式显示。

我遇到的一个问题是:如果我以较小的碎片打破程序以找出错误的位置,错误仍会出现?或者只能在这种特定配置中出现?


回答“如何将AsmJob分配给TStringGrid,以便TStringGrid破坏AsmJob,你能告诉我们吗?”

MyGrid = TStringGrid
  public 
    AsmJob: TAsmJob; 
  end; 

然后在TForm.Create(保存Grid的表单)的某处,我做

MyGrid.AsmJob=AsmJob; 

在MyGrid的析构函数中我做了:

begin 
  FreeAndNil(AsmJob); 
  inherited 
end;

4 个答案:

答案 0 :(得分:14)

此错误表示您的代码损坏了内部内存管理器的结构。当MM检测到这个时,你的调用堆栈代表点。这不是错误路径或与之相关的任何内容。实际错误发生在此刻之前。 它可能与提到的类有关,也可能没有关系。

You should try to use "Range check errors" option (don't forget to make Build, not Compile) and FastMM in full debug mode (with CheckHeapForCorruption, CatchUseOfFreedInterfaces и DetectMMOperationsAfterUninstall options enabled)

你也可以打开FullDebugModeScanMemoryPoolBeforeEveryOperation全局变量,在问题发生后几乎立即得到一个错误,但是这个选项会减慢你的执行速度。

可能最好的选择是定期调用ScanMemoryPoolForCorruptions。在一个地方叫它。出了错误?马上打电话吧。仍有错误?再打电话吧。没错误?你的问题介于最后一次通话之间。现在,您可以使用FullDebugModeScanMemoryPoolBeforeEveryOperation变量来获取精确位置。只需在此代码区域打开它,然后立即将其关闭。

有一个非常类似的错误:“FastMM检测到一个块在被释放后已被修改”。在这种情况下,您的代码不会修改内部结构,而是根本不修改其他内存(“可用内存”)。

顺便说一句,你的错误不是双重的!如果这是一个双重免费调用,FastMM会明确告诉你(很容易检测到,因为你试图释放未使用或不存在的内存块):“已尝试释放/重新分配未分配的块“。

答案 1 :(得分:4)

块头被破坏通常意味着某些东西被覆盖内存,通常是通过做某种不安全的操作。您是否在任何任务中使用原始指针或汇编代码?此外,如果您关闭了范围检查和边界检查,请尝试打开它们并重建。他们可以帮助解决很多这类问题。

答案 2 :(得分:2)

在代码中某处可能存在逻辑竞争,其中正在释放对象。添加NULL检查和其他IPC机制(锁定列表等)以确保不是这种情况。

另一种选择可能是将代码子类化以向其添加日志记录 - 并检查对象是否被顺序访问。

答案 3 :(得分:1)

我正在问几件事,因为我看不到你的代码。

给出以下代码:

procedure TForm1.FormCreate(Sender: TObject);
var
   wObjLst : TObjectList;
begin
   wObjLst := TObjectList.Create;
   try
      wObjlst.OwnsObjects := true;
      wObjlst.Add(TPersistent.Create);
      wObjlst.Add(TPersistent.Create);
   finally
      freeandnil(wObjlst);
   end;
end;

这可以解决错误。

你说明了

  

在运行时,表单创建一个TStringGrid,然后创建AsmJob   创建这两个SAM对象(并从每个磁盘中加载一些数据   他们)。 AsmJob也被分配给网格。当表格被破坏时   Grid通过释放它来处理AsmJob,从而释放了TSam   对象。这是问题所在:第一个对象没有问题   但是第二个在其继承的方法中死亡(在Destroy中   destructor)被称为。

我的第一个问题是如何将AsmJob分配给TStringGrid,以便TStringGrid销毁AsmJob,你能告诉我们吗?

其次,为什么要创建TObjectList的后代来让它存储两个对象,然后释放它们而不是自己创建它们,让TObjectList如上所示销毁它们。

要尝试的另一件事是从fastmm.sourceforge.net下载完整的FastMM4软件包,安装它并使用fulldebug dll来确切地找出哪个对象出现故障。你和我假设它是SAM对象之一,它可能是也可能不是。