views:

471

answers:

3

Hi,

I've created a blank application with a mdi parent form opening a blank child form from the menu.

When the parent form of the child form is set to the mdi - it appears the system does not release memory - thus a leak.

When the parent form is not set, the child form is removed.

Does anyone know why this apparent memory leak can be resolved?

I've been using the ants memory profiler.

Bob.

A: 

One possibility is if you are subscribed to events on an object, it will not be garbage collected. You must make sure nothing is referencing that object.

AaronLS
alas no events are associated - the above comment includes the code used (which is pretty much vanilla).
+1  A: 

I think the most common source of memory leaks are events that are not properly released, but you said you looked for it.

It's hard to know exactly where the leak is without looking at the code. I would recommend you to use .NET Memory Profiler. I've used it before and it seems to be superior than Ants.

jpbochi
the ants profiler is quite good - am using that to find leaks in the real app. However it is via this tool that i have found that i can't even get a basic windows mdi app to lose its handles. I figured if i can't get a windows mdi to not leak memory then i have no chance fixing a complex app. Is there any release calls that need to be made given the above example?
the only way the memory is truly released is if i remove the me.parent = me from the mdi call to the child form - which in effect stops the form from being a mdi child.
I have used .NET Memory Profiler in real apps too and I was able to find leaks even when the only references to lost data were inside framework objs.Anyways, I believe it's possible (but not very likely) that you have found a bug in the framework. The problem is that I can't reproduce it. So, it's very hard to find any solution or workaround, if there's any. Can you share your code with us?
jpbochi
Thanks for the reply.Yes a framework issue may be possible - have heard wispers of that via the web.I'm very happy to share the code - although its not particularly amazing:Steps to reproduce:1. Create a new project (vb.net)2. create a new mdi form3. Create a new blank form - name it Baby4. On the menu up the top add a new button with the following code: Dim frm As New Baby frm.MdiParent = Me frm.Show()Thats all i've done and i still see memory not being released until the entire application is closed.This isn't good as the real application stays open all day.
I have ran some tests on my machine using the step you suggested. I've found out that one Baby form is kept on memory even after all Babys are closed. Researching into the references I discovered that `Form`s have a property named `FormerlyActiveMdiChild`. The MdiParent form keeps a reference to the last closed Baby in this property. It might look like a memory leak, but, in fact, it isn't. Only one instance will be kept there, so the memory profile will not rise. Does that looks like what you've found? Does the number of Babys raise after you create and close several of them?
jpbochi
Turns out the guys behind .NET Memory Profiler found the bug: It's a framework bug. See my answer for a hyperlink and a solution to the problem.
Marc
A: 

This seems to be a bug in the .net framework 2.0 introduced with SP1 and still there in SP2.

Just read the following blog post SciTech software, makers of .net Memory Profiler:
http://www.scitech.se/blog/index.php/2008/03/20/minor-memory-leak-introduced-in-net-framework-20-sp1/

To fix the problem add the following code to your MDI parent form:

protected override void OnMdiChildActivate(EventArgs e)
{
  // Code from http://www.scitech.se/blog/index.php/2008/03/20/minor-memory-leak-introduced-in-net-framework-20-sp1/
  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.
  }
}

I tested this with ANTS Memory Profiler and it fixed the issue in my case.

Marc