Note that there are some explanatory texts on larger screens.

plurals
  1. POFreeing Multiply-referenced Objects
    text
    copied!<p>This is another post about me inheriting an Intraweb app that had a 2MB text file of memory leaks as reported by FastMM4, where I've got it down to 115 instances of one class leaking 52 bytes each.</p> <p>The leaks are from a rather convoluted instantiation and handling of the class. Each instantiation of the class is needed to get the app to work right now. So I'm looking for some ways to either clone the class with some straight-forward cleanup of the clone, or referencing in a different way, or..?</p> <p>The first instantiation of the class (TCwcBasicAdapter) is as a local variable that gets added to a TObjectList (not Owning) and destroyed with the TObjectList (FCDSAdapters):</p> <pre><code>procedure TCwcDeclaration.AttachAdapter(DS: TDataSource; const FormName, KeyFN, TitleFN: string; const Multiple: boolean = False; const AllowAttachment: boolean = False; const AllowComment: boolean = False); var Forms : TCwcSessionForms; Adapter: TCwcCDSAdapter; KeyField, TitleField: TField; begin Forms := GetForms(FormName); KeyField := DS.DataSet.FindField(KeyFN); TitleField := DS.DataSet.FindField(TitleFN); Adapter := TCwcBasicAdapter.Create(DS, KeyField, TitleField, Multiple); Adapter.AttachDBPersist(Self.DBPersist); Forms.AttachDataAdapter(Adapter); Forms.SetAllowAttachments(AllowAttachment); Forms.SetAllowComments(AllowComment); end; procedure TCwcSessionForms.AttachDataAdapter(aCDSAdapter: TCwcCDSAdapter); var Index: integer; begin if (FCDSAdapters.IndexOf(aCDSAdapter) -1) then raise Exception.CreateFmt('Duplicate Adapter attempting to be attached on %0:s', [FFormClassName]); Index := FCDSAdapters.Add(aCDSAdapter); if (FDefaultAdapterIndex = -1) then FDefaultAdapterIndex := Index; end; </code></pre> <p>The second instantiation of the class is also as a local variable that gets added to a TObjectList (not Owning) and destroyed with the TObjectList (FAdapters):</p> <pre><code>procedure TCwcCDSMulticastList.InitializeAdapters(const aSessionForms: TCwcSessionForms); var i, Count: integer; Adapter: TCwcCDSAdapter; TempMulticast: TCwcCDSEventMulticast; begin Count := aSessionForms.GetDataAdapterCount; for i := 0 to Pred(Count) do begin Adapter := aSessionForms.GetDataAdapter(i); TempMulticast := FindDataSource(Adapter.DataSource); if (TempMulticast = nil) then begin TempMulticast := TCwcCDSEventMulticast.Create(Adapter.DataSource); try FMulticastList.Add(TempMulticast); except FreeAndNil(TempMulticast); raise; end; end; TempMulticast.AddObserver(Adapter); FAdapters.Add(Adapter); end; end; </code></pre> <p>The third instantiation of the class is as part of an observer pattern from the TempMulticast.AddObserver(Adapter) line above. The observer is added to TObjectList FObservers (Owning):</p> <pre><code>procedure TCwcCDSEventMulticast.AddObserver(const aCDSAdapter: TCwcCDSAdapter); begin FObservers.Add(TCwcCDSAdapterObserver.Create(aCDSAdapter)); end; constructor TCwcCDSAdapterObserver.Create(const aCDSAdapter: TCwcCDSAdapter); begin inherited Create; FOnStateChange := aCDSAdapter.OnStateChangeIntercept; FOnAfterDelete := aCDSAdapter.AfterDeleteIntercept; FInvalidateCursors := aCDSAdapter.InvalidateCursors; end; </code></pre> <p>The TCwcBasicAdapter is leaked here, not cleaned up when FObservers is destroyed.</p> <p>The latest thing I've tried is changing FObservers to not Owning, creating a private field for the Adapter, freeing the private field in TCwcCDSAdapterObserver.Destroy, but that causes errors.</p> <p>Thanks,</p> <p>Paul Rice</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload