我有一个复杂的应用程序,我刚刚介绍了一些更改,添加了几个带接口的新类,并删除了其他一些。在功能上它一切正常但我在类的Destroy过程之后得到了访问冲突:
“模块'xxxx.exe'中地址0040B984的访问冲突。读取地址80808088”。
我知道这是在该类的'Finalize'代码中,如果我进入反汇编(Delphi 2010),我确实可以看到AV的重点。我看不出一个简单的方法来找出我的哪个变量触发了这个。在深入了解这个过程时是否需要遵循一个程序,这会让我了解被引用的实例的线索?
由于 布赖恩
答案 0 :(得分:13)
在大多数情况下,可以使用FastMM并使用条件定义 FullDebugMode 和 CatchUseOfFreedInterfaces 编译应用程序来捕获此类错误。只需确保将FastMM4放在dpr的“使用”列表中的第一位。
答案 1 :(得分:13)
此错误看起来像您正在使用FastMM进行内存管理。
该错误表示您正在引用已由FastMM清除并具有DebugFillDWord
值的指针。
这意味着您正在使用一个引用已经被释放的对象的接口
这也意味着您尚未启用CatchUseOfFreedInterfaces
。
为了更改这些并进行调试,您无法使用Delphi附带的库存FastMM 您需要下载FastMM(版本4.94)。
下载后:
在[{1}}内已提及gabr,请确保启用FastMM4Options.inc
和FullDebugMode
(禁用CatchUseOfFreedInterfaces
,但您对此不感兴趣后者)。
您可能还想启用CheckUseOfFreedBlocksOnShutdown
;这取决于你当前的堆栈跟踪是否足够好。
当您完成这些设置后,然后通过调试器使用FastMM运行您的应用程序,并在FastMM4单元内的此方法上设置断点:
RawStackTraces
我已经修改了我的FastMM4单元以获得更多上下文信息;我可以与你分享(我已经将它邮寄给FastMM4团队,但它还没有包含在官方消息来源中)。
我写了一篇非常密集的blog article on debugging using FastMM来帮助你 如果需要进一步说明,请在此处留言: - )
祝你好运,如果你需要进一步的指示,请告诉我们。
- 的Jeroen
编辑:20100701 - 强调了Brian评论中提及的内容。
答案 2 :(得分:6)
找到问题的步骤:
我也有这些问题,上面的方法帮助我找到了它们。我的问题是由实现接口的TComponents引起的。假设您有ComponentA和ComponentB,ComponentB实现了一个接口。您将ComponentB(或其接口)分配给ComponentA并存储接口引用。现在ComponentB被破坏,但ComponentA不知道这一点。当您销毁ComponentA时,它会触发接口,调用_Release方法然后获得AV。
解决方法是使用TComponent.FreeNotification。当您收到ComponentB的免费通知时,您将在ComponentA中找不到该界面。我对您的代码一无所知,但如果您的问题类似,您也可以使用FreeNotifications。
编辑添加了第5步
答案 3 :(得分:3)
一个类似的错误,它是一个已经在现有对象上设置的接口引用,当释放所有者对象时,接口引用计数器不会自动减少。它可以在所有者对象的析构函数中使用if Assigned(FMyInterface) then FMyInterface := nil;
来解决。
答案 4 :(得分:3)
我做了类似的事情,对象的析构函数中的以下代码将有所帮助
Destructor TMyObjectThatIAmDoingManualRefCounting.Destroy;
begin
if FMyRefCount<>0 then
messageDlg('You dork, you called Free on me when someone still had references to me');
inherited;
end;
然后你至少可以找到你在哪里释放物体。可能你太早解放了它。过早释放对象实际上不会导致问题,当你释放持有对已经释放的对象的接口引用的对象时,你将得到错误。
你可以做的另一件事是在你的addref和release方法中放置断点,并跟踪谁保持接口引用,以及那些相同的对象是否在之后释放它们。
如果你得到一个接口并以相同的方法释放对象
,那么常见的问题如下所示var
o:TSomeObject;
begin
o:=TSomeObject.Create;
(o as ISomeInterface).DoSomething;
o.free
end;
这会在方法结束时导致AV,因为编译器会创建一个在方法结束时释放的伪接口变量。
你需要这样做
var
o:TSomeObject;
i:ISomeInterface;
begin
o:=TSomeObject.Create;
i:=(o as ISomeInterface); // or Supports or whatever
i.DoSomething;
i:=nil;
o.free
end;
答案 5 :(得分:2)
您的代码中需要注意的一件事是
FInterfacedObject.GetInterface
与
的范围相同FInterfacedObject := TInterfacedObjectClass.Create.
其中FInterfacedObject是一个类变量。
如果你愿意,你可以从内部函数中调用GetInterface,但如果你在创建FInterfacedObject的同一范围内调用GetInterface,无论出于什么原因你都会将引用计数降为0并释放该东西,但它赢了不要,所以如果你这样做
if assigned(FInterfacedObject) then
FInterfacedObject.Free;
您将获得访问冲突。
答案 6 :(得分:2)
可能使用像EurekaLog这样的工具吗? http://delphi.about.com/od/productreviews/ss/eurekalog.htm