我继承了一个Intraweb应用程序,该应用程序具有由FastMM4报告的2MB内存泄漏文本文件。我把它归结为一个类泄漏了52个字节的115个实例。

坏人的简要说明是:

TCwcBasicAdapter = class(TCwcCustomAdapter)  
  protected  
    FNavTitleField: TField;  
    function GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav; override;  
  public  
    constructor Create(aDataSource: TDataSource; aKeyField, aNavTitleField: TField; aMultiple: boolean);  
  end;  

,界面为:

  ICwcCDSAdapterNav = interface(IInterface)  

我是否在错误的树上吠叫,因为该物业被引用计算了?在任何情况下,接口属性都可以防止类被破坏吗?

以下是上述方法的实现:

function TCwcBasicAdapter.GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav;
var
  AdapterNav: TCwcCDSAdapterNavBase;
begin
  result := nil;
  if Assigned(aDataSet) then begin
    AdapterNav := TCwcCDSAdapterNavBasic.Create(aDataSet, FKeyField.Index, FNavTitleField.Index);
    try
      AdapterNav.GetInterface(ICwcCDSAdapterNav, result);
    except
      FreeAndNil(AdapterNav);
      raise;
    end;
  end;
end;

将类声明为:

TCwcCDSAdapterNavBase = class(TInterfacedObject, ICwcCDSAdapterNav)
有帮助吗?

解决方案

FastMM应该为您提供泄漏的内容及其创建位置。
这将有助于将其缩小到真正的罪魁祸首:谁在泄漏什么?

我不确定你的问题究竟是什么?
您的代码不完整或不是有问题的代码:您的类没有Interface属性,也没有Interface private Field,只是一个返回Interface的方法,这是无害的。

编辑:如果没有看到您的Object的代码实现ICwcCDSAdapterNav,我们无法判断它是否确实是引用计数。
如果您不是来自TInterfacedObject 可能>它不是引用计数而您不能依赖此自动释放 ...

您可能需要查看 CodeRage 2会话为傻瓜打击内存泄漏。它主要说明如何使用FastMM来防止/检测Delphi中的内存泄漏。适用于D2007,但仍适用于其他版本。

其他提示

到目前为止,你对FastMM的工作原理有了一些很好的答案。但至于你的实际问题,是的,接口对象可能以两种不同的方式泄漏。

  1. 如果接口所属的对象在其_AddRef和_Release方法中实现了引用计数,则它们仅被引用计数。有些物品没有。
  2. 如果你有循环接口引用,(接口1引用接口2,它引用接口1,那么引用计数永远不会降到0,没有你的一些特殊技巧。如果这是你的问题,我会向你推荐Andreas Hausladen的最近关于这个主题的博客文章。

如果您泄漏了该类的115个实例,那么该类正在泄露。该类占用的内存,而不是它所引用的内存占用的内存,正在泄露。在某个地方,你有115个TCwcBasicAdapter你没有自由的实例。

此外,属性不存储数据,无论它们是接口还是其他类型。只有字段占用内存(以及编译器代表类分配的一些隐藏空间)。

所以,是的,你正在咆哮错误的树。你的内存泄漏在其他地方。当FastMM告诉您内存泄漏时,它不会告诉您每个泄漏实例的分配位置。它具备这种能力;您可能需要调整一些条件编译符号以启用该功能。

但是,该类的实例正在泄漏。 FastMM还应报告其他一些漏洞,例如实现该接口的类或类的实例。


根据你添加的功能,我开始怀疑它确实TCwcCDSAdapterNavBase正在泄漏,这可能是因为你用它来创建它的非典型方式。 GetAdapterNav中的异常处理程序是否运行过?我对此表示怀疑; TObject.GetInterface从不明确提出异常。如果对象不支持该接口,则返回False。所有异常处理程序都可以捕获的内容包括访问冲突和非法操作,无论如何你真的不应该抓住它。

您可以更直接地实现该功能:

if Assigned(FDataSet) then
  Result := TCwcCDSAdapterNavBase.Create(...);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top