.NET Memory Profiler 3.5.130 Released

January 13th, 2010

Yesterday we published a maintenance release of .NET Memory Profiler 3.5 (version 3.5.130). This release contains several important fixes, so it is recommended that you download an install this release if you have an older version installed. For instance, due to refactorings in the previous release, native stack walking failed to use symbols from the Microsoft symbol store, which caused the native allocation call stacks to be much less detailed. We have also improved the performance when working with very large snapshots, and the memory usage has been reduced somewhat. Still, to avoid out of memory problems, it is recommended that the 64-bit version of .NET Memory Profiler is used when profiling applications with high memory usage. The 64-bit version is automatically used when the standalone profiler is used on a 64-bit operating, but since Visual Studio is a 32-bit process, the integrated profiler will only run as 32-bit.

The latest release can be downloaded from the Download page, and more information about the release is available in the release notes.

.NET Memory Profiler 3.5 Released

October 15th, 2009

Finally! Last week we launched .NET MemoryProfiler 3.5. It has taken a while to finish this version, but I’m very pleased with the result. For more information about this version, and to download it, please visit the .NET Memory Profiler site.

.NET Memory Profiler 3.5 Beta Released

September 7th, 2009

It took much longer than planned, but now we have released .NET Memory Profiler 3.5 Beta. It contains significant improvement over the preview, such as a call stack reducer, significantly faster loading and saving of session files, the possibility to ignore analysis issues and support for .NET Framework 4.0. This beta is more or less feature complete and we expect to release the final version of .NET Memory Profiler 3.5 before the end of September. For more information about the beta and to download it, please visit the beta page at http://memprofiler.com/beta. If you have any comments about the new version, you can comment in this blog, or send an e-mail to memprofiler@scitech.se.

Resource Leak in TreeView

April 6th, 2009

I’m planning to restart this blog by writing a few posts about the new features in .NET Memory Profiler  3.5. I’ll start of by investigating a resource leak in the .NET Framework.

I discovered this leak almost a year ago as I investigated memory problems reported by a user (in our support forum). To illustrate the leak, I have created a very simple Windows Forms application, with a form that contains a single button. In the Click handler of the button,  a number of TreeViews are created and the Checkboxes are enabled. They are added to the form, just to make sure that they will be fully initialized and then immediately disposed.

private void button1_Click( object sender, EventArgs e )
{
   for( int i = 0; i < 100; i++ )
   {
      using( TreeView treeView = new TreeView() )
      {
         this.Controls.Add( treeView );
         treeView.CheckBoxes = true;
      }
   }
}

This should not cause any left over instances; neither managed memory instances nor unmanaged resource instances. But when testing this under the profiler, the following results can be seen (after collecting a snapshot before and after a button click).

There are 200 new HBITMAPs and HDCs, and 100 new HIMAGELISTs! Considering that we created 100 TreeViews, it seems very likely that the new resource instances are related to them. Let’s investigate one of the resource further, for example the HBITMAPs. The allocation call stacks of the bitmaps provide the following information:

Thanks to the improved native stacks in .NET Memory Profiler 3.5, you can easily see that the HBITMAP is created as part of an ImageList, when initializing the checkboxes in the native TreeView (TV_InitCheckBoxes). So setting the CheckBoxes property to true, caused the HBITMAP to be created, but why is it not released? At first I suspected that there was actually a resource leak in the native Win32 TreeView implementation, but when checking the documentation, I found this:

Once a tree-view control is created with this style, the style cannot be removed. Instead, you must destroy the control and create a new one in its place. Destroying the tree-view control does not destroy the check box state image list. You must destroy it explicitly. Get the handle to the state image list by sending the tree-view control a TVM_GETIMAGELIST message. Then destroy the image list with ImageList_Destroy.

Apparantly, it’s the responsibility of the user of the native TreeView (e.g. the .NET TreeView control) to release the image list. I find this a bit odd since this image list is created as a side-effect of the internal implementation of the check boxes. Anyway, it seems like the .NET TreeView control fails to release the image list. To fix this leak, the image-list must be explicility released. The ReleaseCheckBoxImageList method below shows an example on how this can be done.

static class TreeViewHelper
{
   ///
   /// Releases the checkbox image list in the
   /// specified TreeView.
   ///
   internal static void ReleaseCheckBoxImageList(TreeView treeView)
   {
      if( treeView.IsHandleCreated )
      {
         int style = GetWindowLong( treeView.Handle, GWL_STYLE );

         if( (style & TVS_CHECKBOXES) != 0 )
         {
            // Checkboxes were enabled in the
            // tree view. Let's destroy the
            // image list.
            IntPtr hStateImageList = SendMessage(
               treeView.Handle,
               TVM_GETIMAGELIST,
               (IntPtr)TVSIL_STATE,
               IntPtr.Zero );

            if( hStateImageList != IntPtr.Zero )
            {
               ImageList_Destroy( hStateImageList );
            }
         }
      }
   }

   #region Windows interop

   const int TV_FIRST = 0x1100;
   const int TVM_GETIMAGELIST = (TV_FIRST + 8);
   const int TVSIL_STATE = 2;
   const int TVS_CHECKBOXES = 0x0100;

   const int GWL_STYLE = (-16);

   [DllImport( "User32" )]
   static extern IntPtr SendMessage(
      IntPtr hWnd, int Msg,
      IntPtr wParam, IntPtr lParam);

   [DllImport( "User32" )]
   static extern int GetWindowLong(
      IntPtr hWnd, int nIndex);

   [DllImport( "comctl32" )]
   [return: MarshalAs( UnmanagedType.Bool )]
   static extern bool ImageList_Destroy(IntPtr himl);

   #endregion
}

This method should be called when the image list will no longer be needed, for instance when the window handle is destroyed. The FixedTreeView class below shows how this can be implemented:

///
/// A TreeView that properly releases
/// native Win32 resources.
///
class FixedTreeView : TreeView
{
   ///
   /// Overridden to make sure that the native
   /// checkbox image list is properly released.
   ///
   protected override void OnHandleDestroyed(EventArgs e)
   {
      TreeViewHelper.ReleaseCheckBoxImageList( this );

      base.OnHandleDestroyed( e );
   }
}

By using the FixedTreeView instead of the standard TreeView, the test program no longer has a resource leak (or memory leak).

As you can see, this fixed the resource leak of HBITMAPs, HIMAGELISTs, HDCs, and even the HeapAlloced memory.

An additional bonus is that this fix will also handle the case where the CheckBoxes property is toggled.  When the CheckBoxes property is set to false, the image list should also be released. Thanks to the fact that the native TreeView must be recreated whenever the checkbox style is updated, the handle will be destroyed when the CheckBoxes property is changed and the fix will executed (“Once a tree-view control is created with this style, the style cannot be removed. Instead, you must destroy the control and create a new one in its place”).

The code in the forum post mentioned in the beginning didn’t handle this correctly, since it used the CheckBoxes property to decide if the image list should be released. This property don’t reflect the whether checkboxes were included in the control being destroyed. Therefore the TVS_CHECKBOXES style is checked instead, as that will handle setting CheckBoxes to false as well.

A beta of .NET Memory Profiler 3.5 will soon be released, but in the meantime you can test the improved native call stacks by downloading the .NET Memory Profiler 3.5 preview.

.NET Memory Profiler 3.5 Preview Released

February 17th, 2009

We didn’t quite make it within two weeks as I wrote in my last post, but now .NET Memory Profiler 3.5 Preview has been released. For more information and to download the preview, visit the .NET Memory Profiler 3.5 Preview page. If you have any comments, questions, or bug reports, we would like to hear about them. Please send any feedback you have to memprofiler@scitech.se.

.NET Memory Profiler 3.1.321 Released (and v3.5 is coming soon)

January 26th, 2009

Today we released a minor maintenance release of .NET Memory Profiler 3.1 (v3.1.321). This release can be downloaded from the .NET Memory Profiler download page. For more information about changes and fixes in this release, check out the release notes.

A more interesting release is the upcoming release of .NET Memory Profiler 3.5. We have put a lot of work into this version and I hope that you will feel that it is a significant improvement over v3.1. Finishing version 3.5 has taken quite a bit longer than we orginally planned, mainly because we started to include features that were initially intended for v4.0. Anyway, it’s soon here. A preview should be available within two weeks. More information will follow, and I really intend to start writing more posts for this blog.

.NET Memory Profiler 3.1.312 Released

August 26th, 2008

Last week we released a maintenance version of .NET Memory Profiler 3.1. The most important update in this version is support for .NET Framework 3.5 SP1. Due to some low-level changes in the runtime, some parts of the profiler didn’t work correctly, in particular the “attach-to” feature and memory dump import.

The new version can be downloaded from http://memprofiler.com/download.aspx. For additional information about what’s new in this release, check the release notes.

.NET Memory Profiler 3.1.301 Released

June 3rd, 2008

Earlier today we released .NET Memory Profiler 3.1.301. This release contains a few fixes related to ASP.NET profiling and the resource tracker. We also recently released .NET Memory Profiler 3.1.297, which contains more significant improvements and fixes to more serious problems. For more information about the latest releases, see the release notes. To download version 3.1.301, go to the download page at http://memprofiler.com/download.aspx.

Minor memory leak introduced in .NET Framework 2.0 SP1

March 20th, 2008

A while ago we received a support request from a customer that had a memory leak in his application. After showing, closing and disposing an MDI child form, the Form instance was still alive. The root path indicated that the child form instance was kept alive by the MDI parent, via the internal propertyStore field. I tried to reproduce the problem using an MDI application that was easily available: the Game of Life application used in the .NET Memory Profiler tutorials. And to my surprise the Game of Life application had a memory leak, even after the memory leak fix in the tutorial had been applied.

After having collected the last snapshot in the second .NET Memory Profiler tutorial (after closing the Game of Life MDI window), there should be no new instances of any type (since the memory leak should have been fixed). Thus if the type filter is set to only show types “With new or removed instances”, the Types list shold be empty. If the original version of .NET Framework 2.0 is used, this is almost true. A single new <GCHandle> instance will exist, but for now I will ignore this (it will be discussed in a future post).

GameOfLife snapshot (without SP)

However, testing the tutorial after having installed .NET Framework 2.0 SP1 shows completely different results (as can be seen in the picture below). Even though no additional instances have been created (Delta is 0), there are still a lot of New and Removed instances.

GameOfLife snapshot (SP1)

At the time of the last snapshot, no Game of Life windows are open, so I would expect all LifeForm instances to be GCed, but there’s still one new live instance left. So the new LifeForm instance is a good candidate for memory leak analysis. The details of the new LifeForm instance is shown in the picture below.

LifeForm instance details

The shown root path of the instance indicates that a reference to the LifeForm instance is stored in a PropertyStore. The PropertyStore class is used internally by WinForms to save space when storing property values. Instead of using instance fields, the dictionary-like PropertyStore is used. Anyway, after doing some digging around using Reflector, I came to the conclusion that the LifeForm instance was put into the PropertyStore using the Form.FormerlyActiveMdiChild property. This is a private property that seems to be only used to update the window icon when an MDI child is deactivated. Below is the code originally used to update the icon:

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

It seems like Microsoft tried to fix a problem with the icon update when the deactivated form was actually closing, so in .NET Framework 2.0 SP1, the code now looks like this:

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:

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 is to use reflection to set the private property “FormerlyActiveMdiChild” to null, for instance in the MdiChildActivate event in the MDI parent. Something like this:

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.
  }
}

Most of the text in this post is copied from my reply to a forum question at http://memprofiler.com/forum/viewtopic.php?t=1160. In the forum I said that the problem was introduced in .NET Framework 3.5. However, installing .NET Framework 3.5 will automatically install .NET Framework 2.0 SP1 and .NET Framework 3.0 SP1, and the memory leak exists in the .NET 2.0 assembly “System.Windows.Forms.dll”.

Unfortunately, this problem affects the .NET Memory Profiler tutorials. When we get the time to update them, we will have to take this into consideration.

In my next post I will make a comment on the single <GCHandle> instance that existed after the last snapshot when using the original .NET Framework 2.0.

.NET Memory Profiler 3.1.283 Released

March 20th, 2008

Yesterday we released .NET Memory Profiler 3.1.283. This release contains a fix for a problem with memory dump imports and attached processes.

If you use the profiler to attach to a process or if you import memory dump files, it is highly recommended that you install this release.

It can be downloaded from http://memprofiler.com/download.aspx.

Several other fixes since the release of .NET Memory Profiler 3.1 are also included in this release. See the release notes for more information about all fixes.