Memory Profile

I tested Release 4.0.0. for Memory Leaks with Redgate ANTS Memory Profiler. I have applied fixes to found leaks in Release 4.0.1.

In particular, in the Demo App, I tested:
- (1) closing a top-level Tab
- (2) closing a User Control within a Tab

There had been issues with the AddUserControl and RemoveUserControl Actions keeping alive controls.

For top-level Tabs, the memory appears now to be 100% clean. If you close a Tab, all objects should be garbage-collected.

EXCEPTION: The only exception to this is Tab 5 which contains a WindowsFormHost and Chart control. I didn't have the time to dig into this deeper as to why this one TabItem5 is being kept alive. I imagine that it is related to either the WindowsFormHost or the Observable.Timer?

For User Controls within a Tab, I modified the code so that it will always lag garbage-collecting merely a single control. If you open a User Control, then close it, it will NOT immediately be garbage-collected. However, the next time you open a new User Control on that tab, it will release the last one for garbage-collection before loading the new one. This is just because the "laggard" needs to maintain the "AddUserControl" Action until the next User Control is loaded . . .

I believe this is a reasonable mitigation.

Also, there was an issue in the DataGridParent with an object being added to ObservableCollection that failed to implement INotifyPropertyChanged (which apparently is a known cause of memory leaks.) This has been fixed:
public class ColumnContent<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : INotifyPropertyChanged

Global Handles

In the Tab Control Service, I manually remove any "global" handles stored in Application.Current.Properties in the Tab Removal code; for example, in Tab Item 10:
Application.Current.Properties["TabItem10RemoveUserControl"] = null;
Application.Current.Properties["TabItem10AddUserControl"] = null;
Application.Current.Properties["RegionOneAction1"] = null;
Application.Current.Properties["RegionOneAction2"] = null;

In a Production application, you could likely use a DependencyInjection/IoC container such as Unity or Ninject to avoid such issues, or roll your own WeakReference dictionary to prevent global handles keeping Tabs alive? However, in the Demo App, I just took the approach of carefully monitoring these hardcoded references and testing them with the Memory Profiler.

Last edited Apr 13, 2013 at 4:52 PM by stagathome0069, version 14


No comments yet.