Memory Leak

Use this forum for questions on how to use .NET Memory Profiler and how to analyse memory usage.

Moderator: SciTech Software

Memory Leak

Postby kgoodrich » Wed Dec 06, 2006 10:23 pm

I have an application that has an apparent memory leak. From the looks of it, it is caused because there is a remaining reference to a form that has been disposed, but it is not being garbage collected. After a while of running the application, my memory continually rises to the point of using up 130000K. From my understanding, the root path window is supposed to show why the object is not being garbage collected. I have gotten all the way to the root path, but cannot find anything pointing me in the direction of the cause of my memory leak. I will post the root path list below. There is only 1 of 1 root paths that show up for my instance of the form:

System EventHandler #17,339
System.Windows.Forms MenuItem.MenuItemData #16,894
System.Windows.Forms MenuItem #17,338
System.Collections Hashtable.bucket[] #7,730
System.Collections Hashtable #7,731
System.Windows.Forms MenuItem allCreatedMenuItems


Can someone point me in the right direction of solving this problem.
Kendal Goodrich
kgoodrich
 
Posts: 4
Joined: Wed Dec 06, 2006 9:28 pm

Postby Andreas Suurkuusk » Thu Dec 07, 2006 8:53 am

Hi,

Your memory problem is probably caused by a bug in MenuItem. Are you using .NET Framework 1.1? A while ago I replied to a similar problem in the microsoft.public.dotnet.framework.windowsforms newsgroup, and that post might be relevant for your problem as well. Below is the post from the newsgroup:

I did a quick check of this memory leak. Using our profiler it was easy to
see that the Form is being referenced by a MenuItem that has been added to
the static Hashtable "allCreatedMenuItems". By disassembling the MenuItem
class it's also quite easy to see what's causing the MenuItem to be added to
the hashtable. When the menuitem is shown AND when it's updated, a
MENUITEMINFO class is created. When creating the MENUITEMINFO a uniqueId for
the MenuItem is assigned (allowing the MenuItem to be identified when
receiving Win32 messages). The MenuItem is then added to the
"allCreatedMenuItems" hashtable. In the Dispose function the MenuItem is
removed from this hashtable. The problem is that the MenuItem is added to
the hashtable, with a new uniqueId, each time the MenuItem is updated.

The following code can be found in MenuItem.CreateMenuItemInfo:

Code: Select all
<snip>
this.uniqueId = ++MenuItem.createdMenuItemsCounter;
MenuItem.allCreatedMenuItems.Add( this.uniqueId, this );
</snip>


If the above code was replaced with the following, there would be no memory
leak:

Code: Select all
<snip>
if( uniqueId == -1 ) // uniqueId is assigned to -1 in the constructor.
{
  this.uniqueId = ++MenuItem.createdMenuItemsCounter;
  MenuItem.allCreatedMenuItems.Add( this.uniqueId, this );
}
</snip>


Another sideeffect of this bug is that the allCreatedMenuItems hashtable
grows each time a MenuItem is changed (e.g. changing the Enable property),
and never shrinks (except for one entry being removed in MenuItem.Dispose).

The problem with the growing hashtable has actually been reported as a bug
previously in this newsgroup.

The only workaround I can come to think of is to use reflection to explictly
remove all added entries from the hashtable.

Something like:

Code: Select all
static Hashtable allCreatedMenuItems;
void DisposeMenu( Menu menu )
{
  if( allCreatedMenuItems == null )
  {
    Type miType = typeof( MenuItem );
    FieldInfo htField = miType.GetField( "allCreatedMenuItems",
    BindingFlags.Static | BindingFlags.NonPublic );
    allCreatedMenuItems = (Hashtable)htField.GetValue( null );
  }

  // Find out keys to remove.
  ArrayList keysToRemove = new ArrayList();
  foreach( DictionaryEntry de in allCreatedMenuItems )
  {
    if( de.Value == menu )
      keysToRemove.Add( de.Key );
  }
  // And remove them.
  foreach( object key in keysToRemove )
  {
    allCreatedMenuItems.Remove( key );
  }

  // Dispose children
  foreach( MenuItem mi in menu.MenuItems )
  {
    DisposeMenu( mi );
  }
}

Add the above code to the Dispose method of the Form containing the Menu
(the Menu and all its MenuItems should already have been Disposed, which is
done automatically by the code generated by the forms designer):

Code: Select all
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
  if( disposing )
  {
    if (components != null)
    {
      components.Dispose();
    }
    DisposeMenu( contextMenu1 );
  }
  base.Dispose( disposing );
}

I hope this solves your problems and that this message answers your question
in the e-mail you sent to us.
Best regards,

Andreas Suurkuusk
SciTech Software AB
Andreas Suurkuusk
 
Posts: 863
Joined: Wed Mar 02, 2005 7:53 pm
Location: Sweden

Postby kgoodrich » Thu Dec 07, 2006 9:58 pm

Thanks, that helps me get started, but I have run into another issue. The application I am tring to profile also seems to increase the handle count in the task manager. It seems to increase and not decrease. I used an application called handle by SysInternals and ran it to determine that it is a handle of type mutant that keeps increasing and never decreasing. Now how do I go about finding my problem from here. I never directly handle any mutexs in my code that I am aware of. Any suggestions?????????
Kendal Goodrich
kgoodrich
 
Posts: 4
Joined: Wed Dec 06, 2006 9:28 pm

Postby Andreas Suurkuusk » Sun Dec 10, 2006 9:56 pm

Hi,

Have you tried to install .NET Memory Profiler 3.0 Preview? This version includes an unmanaged resources tracker that provides information on why and how the mutexes are created. This information can hopefully help you investigate the problem with leaking mutexes.

For more information about .NET Memory Profiler see http://memprofiler.com/preview
Best regards,

Andreas Suurkuusk
SciTech Software AB
Andreas Suurkuusk
 
Posts: 863
Joined: Wed Mar 02, 2005 7:53 pm
Location: Sweden

Postby kgoodrich » Mon Dec 11, 2006 2:54 pm

I am running a trial version of Net Mem Profiler 2.6 so I cannot run the 3.0 Preview. Are there any other methods I can use to troubleshoot this problem????
Kendal Goodrich
kgoodrich
 
Posts: 4
Joined: Wed Dec 06, 2006 9:28 pm

Postby Andreas Suurkuusk » Mon Dec 11, 2006 10:37 pm

We will soon release .NET Memory Profiler 3.0 Beta and it will be possible to request a trial key for that version. Other than that I don't have any suggestion on how to investigate your mutex problem.
Best regards,

Andreas Suurkuusk
SciTech Software AB
Andreas Suurkuusk
 
Posts: 863
Joined: Wed Mar 02, 2005 7:53 pm
Location: Sweden

Postby kgoodrich » Mon Dec 11, 2006 10:42 pm

UPDATE: I just found out what is specifically causing my handle count to increase....It is Microsoft's InkOverlay class. I am using this class because this application will be running on a tablet as well as a desktop. I was not specifically disposing of the InkOverlay object. I use a custom RichTextBox that incorporates the InkOverlay class. In the RichTextBox's dispose method I tried to dispose of the InkOverlay instance. Now when the form is instantiated, my handle count goes up by 10 and when I close the form, the handle count drops by 5. So I still have a problem with 5 handles not being removed. If I commented out the code that says new InkOverlay(), my handle count does not go up or down at all. Any suggestions about using the inkoverlay class????
Kendal Goodrich
kgoodrich
 
Posts: 4
Joined: Wed Dec 06, 2006 9:28 pm


Return to Using .NET Memory Profiler

Who is online

Users browsing this forum: No registered users and 5 guests

SciTech Software logo

© Copyright 2001-2013. SciTech Software AB
All rights reserved.


SciTech Software AB
Kartvägen 21
SE-175 46 Järfälla
Sweden


E-mail: mail@scitech.se

Telephone: +46-706868081