Memory leaks in a Windows Forms application

2019-01-17 06:51发布

We are developing a big .NET Windows Forms application. We are facing a memory leak/usage problem in that despite we are disposing the forms.

The scenario is like:

  1. Our application is using 60 KB of memory with a list of records displaying in a grid.
  2. When the user clicks on a record it opens a form, myform.showDialog, show the details. The memory jumps from 60 KB to 105 MB.
  3. Now we close the form myform to get back to grid, and dispose that form and set it to null. Memory remains at 105 MB.
  4. Now if we again perform step 2, it would jump from 105 MB to 150 MB and so on.

How can we free up the memory when we close myForm?

We have already tried GC.Collect(), etc., but without any result.

8条回答
来,给爷笑一个
2楼-- · 2019-01-17 07:21

I recently had a similar issue where a running timer kept the form in memory, even though the form was closed. The solution was to stop the timer before closing the form.

查看更多
ゆ 、 Hurt°
3楼-- · 2019-01-17 07:22

Some third party controls have errors in their code. It may not be your issue if you're using some of those controls.

查看更多
萌系小妹纸
4楼-- · 2019-01-17 07:25

Check that you have completely removed all the references to the form. Sometimes may happen that you have some hidden references done that you did not notice.

For example: if you attach to external events from your dialog, that is, to events of an external window, if you forget to dettach from them you will have a remaining reference to your form that will never disappear.

Try this code into your dialog (example bad code...):

   protected override void OnLoad(EventArgs e)
   {
       Application.OpenForms[0].Activated += new EventHandler(Form2_Activated);
       base.OnLoad(e);
   }

   void Form2_Activated(object sender, EventArgs e)
   {
       Console.WriteLine("Activated!");
   }        

And open and close the dialog many times, you will se the number of strings in the console grow for each call. This means that the form remains in memory even if you called to dispose (that should only be used for releasing unmanaged resources, i.e.: closing a file and things like this).

查看更多
倾城 Initia
5楼-- · 2019-01-17 07:30

Disposing the forms is not necessarily a guarantee that you are not leaking memory. For example, if you are binding it to a dataset but you are not disposing of the dataset when you are done, you will probably have a leak. You may need to use a profiling tool to identify which disposable resources are not being released.

And btw, calling GC.Collect() is a bad idea. Just saying.

查看更多
我只想做你的唯一
6楼-- · 2019-01-17 07:34

I have not seen your code but this is the most likely scenario:

1) Your form gets closed but there is a reference to it hanging there and cannot be garbage collected.

2) You are loading some resource that does not get freed up

3) You are using XSLT and compile it everytime you transform

4) You have some custom code that gets compiled and loaded at runtime

查看更多
【Aperson】
7楼-- · 2019-01-17 07:36

The most common source of memory leaks in Windows Forms applications is event handlers that remain attached after form disposal...so this is a good place to start your investigation. Tools like http://memprofiler.com/ can help greatly in determining roots for instances that are never being GC'd.

As for your call to GC.Collect

  1. It's definitely not good to do this in practice
  2. In order to make sure your GC collect really does collect as much as possible, you need to make multiple passes and wait for pending finalizers, so the call is truly synchronous.

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    

Also, anything that holds on to your instance of your form will keep the form around in memory, even after it's been Closed and Disposed.

Like:

static void Main() {
    var form = new MyForm();
    form.Show();
    form.Close();

    // The GC calls below will do NOTHING, because you still have a reference to the form!
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();

    // Another thing to not: calling ShowDialog will NOT 
    // get Dispose called on your form when you close it.
    var form2 = new MyForm();
    DialogResult r = form2.ShowDialog();

    // You MUST manually call dispose after calling ShowDialog! Otherwise Dispose 
    // will never get called.
    form2.Dispose();

    // As for grids, this will ALSO result in never releasing the form in
    // memory, because the GridControl has a reference to the Form itself
    // (look at the auto-generated designer code).
    var form3 = new MyForm();
    form3.ShowDialog();
    var grid = form3.MyGrid;

    // Note that if you're planning on actually using your datagrid
    // after calling dispose on the form, you're going to have
    // problems, since calling Dipose() on the form will also call
    // dispose on all the child controls.
    form3.Dispose();
    form3 = null;
}
查看更多
登录 后发表回答