Delphi 2009 - Can an interface property cause a memory leak?

I inherited an Intraweb application that had a text file with 2 MB of memory leaks, according to FastMM4. I got this up to 115 instances of the same class, passing 52 bytes.

Short description of a bad actor:

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

and interface:

  ICwcCDSAdapterNav = interface(IInterface) 

Am I barking the wrong tree since the property is counted by reference? Are there any circumstances where an interface property may prevent the class from being destroyed?

Here is the implementation of the method above:

 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; 

with a class declared as:

 TCwcCDSAdapterNavBase = class(TInterfacedObject, ICwcCDSAdapterNav) 
+4
source share
3 answers

FastMM should give you what leaked and where it was created.
This will help narrow it down to the real culprit: who flows what?

I'm not sure what is your question? Your code is incomplete or not the one in question: your class does not have an interface property or private interface field, but just a method that returns an interface that is harmless.

Change Without seeing the code of your object that implements ICwcCDSAdapterNav, we cannot determine whether it is actually calculated by reference.
If you do not step down with TInterfacedObject , chances are that it does not refer to counting and that you cannot rely on this automatic release ...

You can watch this CodeRage 2 : Combating Memory Leaks for Dummies session . This basically shows how to use FastMM to prevent / detect memory leaks in Delphi. Was for D2007, but still relevant for other versions.

+4
source

You have some good answers on how FastMM works. But as for your actual question, yes, conjugated objects can flow in two different ways.

  • Interfaces refer only to reference counting if the objects to which they belong have implemented reference counting in their _AddRef and _Release methods. Some objects do not.
  • If you have links to a circular interface, (interface 1 refers to interface 2, which refers to interface 1), then the link counter will never drop to 0 without any special tricks on your part. If this is your problem, I refer you to Andreas Hausaden a recent related blog post.
+4
source

If you miss 115 instances of this class, then this is the class that leaked. The memory occupied by this class, and not the memory occupied by the things to which it refers, leaks out. Somewhere you have 115 instances of TCwcBasicAdapter that you are not freeing.

In addition, properties do not store data, regardless of whether they are interfaces or some other type. Only the fields take up memory (along with some hidden space that the compiler allocates for the class name).

So yes, you bark the wrong tree. Your memory leak is somewhere else. When FastMM tells you that you have a memory leak, doesn’t it also tell you where each missing instance was allocated. He has that ability; You may need to configure some conditional compilation characters to enable this feature.

Of course, these are not only leaks of this class. FastMM should also report other leaks, such as class instances or classes that implement the interface.


Based on the function you added, I began to suspect that it really is TCwcCDSAdapterNavBase that is TCwcCDSAdapterNavBase , and this may be due to the atypical way you use to create it. Is an exception handler GetAdapterNav in GetAdapterNav ? I doubt it; TObject.GetInterface never explicitly throws an exception. If the object does not support the interface, it returns False . All that an exception handler can catch is things like access violations and illegal operations, which you really shouldn't catch there anyway.

You can implement this function more directly as follows:

 if Assigned(FDataSet) then Result := TCwcCDSAdapterNavBase.Create(...); 
+2
source

Source: https://habr.com/ru/post/1286652/


All Articles