代码之家  ›  专栏  ›  技术社区  ›  Brian Frost

如何在Delphi中找到引起AV的悬空接口

  •  11
  • Brian Frost  · 技术社区  · 15 年前

    我知道这是在'敲定'类的代码,并确信如果我进入分解(德尔福2010年)一步,我可以看到的AV点。我看不到一个简单的方法来找出我的变量触发了这个。有没有一个程序要遵循时,深入到这将得到一个线索,我的实例是指?

    谢谢

    7 回复  |  直到 15 年前
        1
  •  14
  •   Community Mohan Dere    8 年前

    此错误看起来像是在使用FastMM进行内存管理。 DebugFillDWord

    这意味着您使用的接口引用的对象已经被释放。
    CatchUseOfFreedInterfaces

    为了更改这些,并进行调试,您不能使用Delphi附带的stock FastMM。
    FastMM (版本4.94)。

    下载后:

    就像 gabr 已经提到了,里面 FastMM4Options.inc ,请确保启用 FullDebugMode (这将禁用 CheckUseOfFreedBlocksOnShutdown ,但您现在对后者不感兴趣)。
    您可能需要启用 RawStackTraces 也;这取决于当前堆栈跟踪是否足够好。

    完成这些设置后, 通过调试器使用FastMM运行应用程序,并在FastMM4单元内的此方法上放置断点:

    procedure TFreedObject.InterfaceError;
    

    我已经修改了我的FastMM4单元一点,以获得更多的上下文信息;我可以和你分享(我已经把它寄给了FastMM4团队,但是还没有包含在官方资料中)。

    我写了一篇很密集的文章 blog article on debugging using FastMM
    如果需要进一步解释,请在此处留言:-)

    --杰罗恩

    编辑

        2
  •  13
  •   gabr    15 年前

    在大多数情况下,可以通过使用 FastMM 完全调试模式 使用自由接口

        3
  •  6
  •   The_Fox    15 年前

    查找问题的步骤:

    1. 按照Gabr的建议,在fulldebugmode中使用FastMM(我想您已经这样做了,看看8080模式)。
    2. 在销毁过程中将类中使用的所有接口显式设置为nil
    3. 在销毁过程的开始处放置一个断点
    4. 当你在没有任何问题的情况下关闭了所有接口之后仍然拥有AV时,对父类执行步骤2-5。

    我也遇到过这些问题,上面的方法帮我找到了。我的问题是由实现接口的TComponents引起的。假设您有ComponentA和ComponentB,ComponentB实现了一个接口。将ComponentB(或其接口)分配给ComponentA并存储接口引用。现在ComponentB被销毁了,但是ComponentA不知道。当您销毁ComponentA时,它会关闭接口,调用\u Release方法并获得AV。

    解决方法是使用TComponent.FreeNotification。当您收到来自ComponentB的免费通知时,您将禁用ComponentA中的接口。我不知道你的代码,但如果你的问题是类似的,你也可以与免费通知。

    编辑:

        4
  •  3
  •   mjn anonym    15 年前

    一个类似的错误,咬了我是一个接口引用已经设置了一个现有的对象,接口引用计数器不会自动减少时,所有者对象被释放。这可以用一个简单的方法来解决 if Assigned(FMyInterface) then FMyInterface := nil; 在所有者对象的析构函数中。

        5
  •  3
  •   Dave Novo    15 年前

    我做了一个类似的事情,下面的代码在你的对象的析构函数中将有所帮助

    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;
    

    var
      o:TSomeObject;
      i:ISomeInterface;
    begin
      o:=TSomeObject.Create;
      i:=(o as ISomeInterface); // or Supports or whatever
      i.DoSomething;
      i:=nil;
      o.free
    end;
    
        6
  •  2
  •   Peter Turner    15 年前

    要在代码中查找的一件事是

    FInterfacedObject.GetInterface 
    

    范围与

    FInterfacedObject := TInterfacedObjectClass.Create.
    

    其中FInterfacedObject是一个类变量。

    如果愿意,可以从内部函数调用GetInterface,但是如果在创建FInterfacedObject的同一范围内调用GetInterface,无论出于何种原因,都会将引用计数降至0并释放该对象,但它不会为零,因此如果这样做

    if assigned(FInterfacedObject) then
        FInterfacedObject.Free;
    

    你会被侵犯访问权限。

    推荐文章