This is a simple test application to help understand WPF memory usage. They key thing I want to understand is why MainWindow
is still referenced and it's memory not released, even after being closed and having waited for GC finalization?
(See code listing below)
The text "MainWindow finalizer" is not executed by the time of snapshot #2, which seems unexpected. To investigate, I have taken two memory snapshots using VS diagnostic tools at the points indicated in the code listing.
Here's the VS comparison of the two snapshots:
This shows that the MainWindow
is still around. But why, if nothing is referencing it? Drilling down (again using the diagnostic tools) it turns out that there is a reference after all:
There are other objects also referencing the MainWindow
, but they all eventually form a cycle back to it, so I do not think they are genuinely "root" objects which are keeping the reference alive. But for the MediaContext
/ Dispatcher
duo this is not the case.
The Dispatcher
as I understand it is run once per thread so that seems OK by itself. But what's up with the MediaContext
that it owns, which in turns holds onto my MainWindow
?
Is this normal? Is it a "memory leak"? Why does it happen?
Also, importantly how can I / should I actually get rid of the MainWindow
object?
App.xaml:
<Application
x:Class="memtest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:memtest"
StartupUri="MainWindow.xaml"
Startup="Application_Startup"
>
<Application.Resources/>
</Application>
App.xaml.cs:
namespace memtest
{
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
// *** SNAPSHOT 1 ***
ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
MainWindow window = new MainWindow();
window.Show();
window.Close();
window = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// *** SNAPSHOT 2 ***
}
}
}
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Debug.WriteLine("MainWindow constructor");
}
~MainWindow()
{
// Never reached
Debug.WriteLine("MainWindow finalizer");
}
}
MainWindow.XAML is the default created by VS, which contains only an empty grid.
There is no other code in the project.
This is a .NET 4.72 project.
This is not quite a dupe of A WPF window doesn't release the memory after closed, because it did not use WaitForPendingFinalizers()
nor did it use an explicit finalizer. And that question has no valid answers.