我一直在阅读有关 WPF 内存处理的内容,并跟踪了前 5 个和前 8 个内存泄漏陷阱,但在我目前的情况下没有任何帮助。
我的软件有一个问题,WPF 在程序终止之前不会释放内存。如果我永远让它消失,无论我做什么都会导致 OutOfMemoryException。我已经设法在一个小样本中隔离该问题,以展示它如何不释放其内存,即使我不再使用它。这是我重现问题的方法:
我创建了 2 个项目,1 个控制台程序和 1 个 WPF 应用程序。在我的 WPF 应用程序中,我有一个 MainWindow.xaml,其中没有任何内容:
<Window x:Class="MemoryLeakWpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MemoryLeakWpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="MainWindow_OnLoaded">
<Grid>
</Grid>
</Window>
我确实订阅了 Loaded 事件,我用它来立即关闭窗口,可以在此处的 .cs 文件中看到:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Debug.WriteLine("Constructing",GetType().Name);
}
~MainWindow()
{
Debug.WriteLine("Deconstructing", GetType().Name);
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
Close();
}
}
我还在构造函数和解构函数中添加了调试行,以便我可以跟踪它的创建和丢弃时间。然后,我在 WPF 应用程序中创建一个 Controller 类,它代表此 WPF 类库的入口点,该类库具有创建和显示窗口的方法:
public class Controller
{
public void Execute()
{
MainWindow window = new MainWindow();
window.ShowDialog();
Debug.WriteLine("Constructing", GetType().Name);
}
~Controller()
{
Debug.WriteLine("Deconstructing", GetType().Name);
}
}
这里我还添加了调试跟踪线。我没有 App.xaml,因为此 WPF 项目在其属性中设置为类库。那是 WPF 部分。在控制台项目中,我将以下代码添加到我的主类中:
[STAThread]
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
Controller controller = new Controller();
Console.WriteLine("Test " + i);
controller.Execute();
}
Console.WriteLine("Pressing enter will close this");
Console.ReadLine();
Debug.WriteLine("Party is over, lets leave");
}
所以基本上的设置是我有一个想要显示对话框的控制台类。它为 WPF 应用程序创建控制器并调用 Execute。控制器显示加载完成后立即关闭的窗口。然后控制台类创建一个新的控制器来重新执行该过程。现在,这是我在输出中看到的内容:
MainWindow: Constructing
Controller: Constructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
控制器正在构造和解构,但窗口却没有。但是,当 for 循环完成并且我按 Enter 键让程序运行时,我得到以下结果:
Party is over, lets leave
MainWindow: Deconstructing
Controller: Deconstructing
MainWindow: Deconstructing
Controller: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
突然间,MainWindow 的所有实例现在都在解构,但只有在程序运行完时,而不是在我们丢弃 for 循环中的引用时。这意味着在我们的程序中,在发生 OutOfMemoryException 之前,我们只能打开有限次数的窗口。
但价值百万美元的问题是:如何说服 WPF 在程序运行时而不是在程序关闭时释放其内存?