Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A WPF window doesn't release the memory after closed

I created a test code:

private void Application_Startup_1(object sender, StartupEventArgs e)
{
    ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
    MainWindow window = new MainWindow();
    window.Show();
    window.Close();
    window = null;
    GC.Collect();
}

The MainWindow is a automatic created window by Visual Studio and I haven't add any code to it. Before the line "MainWindow window = new MainWindow();", the application occupies 4M memory. When the window is opened, it became 13M. It doesn't change even if we close the window and call the GC.Collect()

What are these extra memory being used for and how can we release them?

like image 771
Terry Avatar asked Jan 19 '13 04:01

Terry


1 Answers

Your test code is flawed, see here for my comments on an almost identical scenario.

Yours is a bit simpler but same comments apply:

  • setting a variable null and calling GC.Collect is not enough. The JIT is allowed to optimize your assignment to window = null; away because it can clearly see the variable is not used anymore afterwards. Furthermore GC reporting of stack frames is not exact (with respect to your source), there may be hidden copies on the stack. Move the test code into a separate method which you return from, to make sure no references to MainWindow are left on the stack. (Technically not necessary after fixing the next point, but I'm mentioning it for completeness so people understand that point when writing GC tests.)
  • you are not giving the multithreaded WPF rendering engine time to clean up, closing and forcing GC is not enough to synchronize with the rendering engine to clean up its resources

In addition your GC.Collect call is not enough to collect objects with finalizers, you need

GC.Collect(); // find finalizable objects
GC.WaitForPendingFinalizers(); // wait until finalizers executed
GC.Collect(); // collect finalized objects

See the linked post for a more complete example, after fixing it I could not reproduce any leaked window instance.

What are these extra memory being used for and how can we release them?

Besides the flaws in your test code, by looking at memory consumption you may be looking at the wrong thing. Don't look at memory alone, use debugger tools which can inspect live objects. The .NET runtime will anticipate more allocations and not give memory back to the OS immediately, this is not a leak, the OS is perfectly capable to page out unused memory if the runtime doesn't use it. A leak is only present if it keeps growing if you repeat the operation.

like image 57
Zarat Avatar answered Sep 20 '22 07:09

Zarat