short rootpath

Use this forum for questions on how to use .NET Memory Profiler and how to analyse memory usage.
Post Reply
stijn
Posts: 23
Joined: Thu Jun 28, 2007 2:57 pm

short rootpath

Post by stijn » Fri Jan 11, 2008 3:00 pm

Hi, another rootpath that leaves me clueless

System.Windows.Forms PropertyStore.ObjectEntry[]
System.Windows.Forms PropertyStore
DIASUI frmMain
System.Windows.Forms Application.ThreadContext
System.Windows.Forms Application.ComponentManager System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int, int, int)


frmMain is my main program, so its normal that this one is still in memory . the rootpath contains to a control that was shown as a MDI child and should be disposed now (marked as disposed, but still active )

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Sun Jan 13, 2008 10:49 pm

This problem is probably caused by a newly introduced bug (in .NET Framework 3.5). I recently had a user report about a similar issue, and I found out that a change in the code that manages MDI children caused a closed MDI form to be kept in memory.

When an MDI form is deactivated, a reference to the form is stored in the FormerlyActiveMdiChild property of the MDI parent form. This property is used to update the icon of the deactivated form. Below is the code used (internally by .NET) to update the icon:

Code: Select all

if( this.FormerlyActiveMdiChild != null ) 
{
    this.FormerlyActiveMdiChild.UpdateWindowIcon(true);
    this.FormerlyActiveMdiChild = null;
}
It seems like Microsoft tried to fix a problem with the icon update while the deactivated form was actually closing, so in .NET Framework 3.5, the code now looks like this:

Code: Select all

if( this.FormerlyActiveMdiChild != null && 
    !this.FormerlyActiveMdiChild.IsClosing ) 
{
    this.FormerlyActiveMdiChild.UpdateWindowIcon(true);
    this.FormerlyActiveMdiChild = null;
}
However, this causes the assignment “this.FormerlyActiveMdiChild = null” to be skipped and a reference is left to the closed (and possibly disposed) MDI form. This prevents it (and all its child instances) from being GCed.

It would probably be more correct if the original code was changed to:

Code: Select all

if( this.FormerlyActiveMdiChild != null ) 
{
    if( !this.FormerlyActiveMdiChild.IsClosing )
      this.FormerlyActiveMdiChild.UpdateWindowIcon(true);

    this.FormerlyActiveMdiChild = null;
}
Note that this memory leak only causes a single form (and its child instances) to be kept in memory. If you open and close another form, the original form will become eligible for GC (i.e. the memory leak doesn’t grow over time). Nonetheless, it is preferable to make sure that all unused instances are correctly GCed. One workaround to this problem might be to use reflection to set the private property “FormerlyActiveMdiChild” to null, for instance in the MdiChildActivate event in the MDI parent. Something like this:

Code: Select all

protected override void OnMdiChildActivate( EventArgs e )
{
  base.OnMdiChildActivate( e );
  try
  {
    typeof( Form ).InvokeMember( "FormerlyActiveMdiChild",
      BindingFlags.Instance | BindingFlags.SetProperty |
      BindingFlags.NonPublic, null,
      this, new object[] { null } );
  }
  catch( Exception )
  {
    // Something went wrong. Maybe we don't have enough permissions
    // to perform this or the "FormerlyActiveMdiChild" property 
    // no longer exists.
  }
}
Best regards,

Andreas Suurkuusk
SciTech Software AB

stijn
Posts: 23
Joined: Thu Jun 28, 2007 2:57 pm

Post by stijn » Wed Jan 16, 2008 2:11 pm

indeed, only the first form stays in memory.
it happens in c# 2.0 tho, we havent moved to 3.5 yet

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Wed Jan 16, 2008 9:58 pm

I'm not sure that your problem is caused by the "FormerlyActiveMdiChild" property, but the root path is identical (the "FormerlyActiveMdiChild" property is stored in a PropertyStore).

Note that you don't have to specifically use .NET Framework 3.5 for this problem to occur, it just needs to be installed. Installing .NET Framework 3.5 will cause the .NET Framework 2.0 assemblies to be updated as well (e.g., System.Windows.Forms.dll).

Do you have .NET Framework 3.5 installed? Did you try the workaround I presented?
Best regards,

Andreas Suurkuusk
SciTech Software AB

cwesty
Posts: 1
Joined: Thu Feb 14, 2008 7:29 pm

Post by cwesty » Thu Feb 14, 2008 7:33 pm

For the record, this post was exactly right. The fix posted took care of the problem. We also were targeting framework 2.0 but had 3.5 installed.

Thanks much!

Post Reply

Who is online

Users browsing this forum: No registered users and 12 guests