我有这个令人讨厌的错误,它在过去消失了,但现在经过一段时间它又回来了。
我有两个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;
答案 0 :(得分:14)
此错误表示您的代码损坏了内部内存管理器的结构。当MM检测到这个时,你的调用堆栈代表点。这不是错误路径或与之相关的任何内容。实际错误发生在此刻之前。 它可能与提到的类有关,也可能没有关系。
你也可以打开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对象之一,它可能是也可能不是。