Delphi 2009 - 接口属性是否会导致内存泄漏?
-
10-07-2019 - |
题
我继承了一个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的工作原理有了一些很好的答案。但至于你的实际问题,是的,接口对象可能以两种不同的方式泄漏。
- 如果接口所属的对象在其_AddRef和_Release方法中实现了引用计数,则它们仅被引用计数。有些物品没有。
- 如果你有循环接口引用,(接口1引用接口2,它引用接口1,那么引用计数永远不会降到0,没有你的一些特殊技巧。如果这是你的问题,我会向你推荐Andreas Hausladen的最近关于这个主题的博客文章。 醇>
如果您泄漏了该类的115个实例,那么该类正在泄露。该类占用的内存,而不是它所引用的内存占用的内存,正在泄露。在某个地方,你有115个TCwcBasicAdapter
你没有自由的实例。
此外,属性不存储数据,无论它们是接口还是其他类型。只有字段占用内存(以及编译器代表类分配的一些隐藏空间)。
所以,是的,你正在咆哮错误的树。你的内存泄漏在其他地方。当FastMM告诉您内存泄漏时,它不会告诉您每个泄漏实例的分配位置。它具备这种能力;您可能需要调整一些条件编译符号以启用该功能。
但是,该类的仅实例正在泄漏。 FastMM还应报告其他一些漏洞,例如实现该接口的类或类的实例。
根据你添加的功能,我开始怀疑它确实TCwcCDSAdapterNavBase
正在泄漏,这可能是因为你用它来创建它的非典型方式。 GetAdapterNav
中的异常处理程序是否运行过?我对此表示怀疑; TObject.GetInterface
从不明确提出异常。如果对象不支持该接口,则返回False
。所有异常处理程序都可以捕获的内容包括访问冲突和非法操作,无论如何你真的不应该抓住它。
您可以更直接地实现该功能:
if Assigned(FDataSet) then
Result := TCwcCDSAdapterNavBase.Create(...);