gpt4 book ai didi

WPF 窗口在程序终止之前不会释放其资源

转载 作者:行者123 更新时间:2023-12-04 10:24:17 24 4
gpt4 key购买 nike

我一直在阅读有关 WPF 内存处理的内容,并跟踪了前 5 名和前 8 名内存泄漏陷阱,但在我目前的情况下没有任何帮助。

我的软件有一个问题,WPF 在程序终止之前不会释放它的内存。如果我让它永远消失,无论我做什么都会导致 OutOfMemoryException。我设法在一个小样本中隔离了这个问题,以展示它是如何不释放内存的,即使我不再使用它。这是我如何重现问题:

我创建了 2 个项目,一个控制台程序和一个 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 应用程序创建 Controller 并调用 Execute。 Controller 显示完成加载后立即关闭的窗口。然后控制台类创建一个新的 Controller 来重新执行这个过程。现在,这就是我在输出中看到的:
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

Controller 正在构造和解构,但窗口不是。但是,当 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 在程序运行时而不是在程序关闭时释放其内存?

最佳答案

您声称自己是 [STAThread]但是你没有消息泵。没有消息泵,您就不是真正的 STA。在这种特殊情况下,这意味着 WPF 永远没有机会清理其资源。 WPF 可能将消息发布到消息队列,而这些消息从未被接收。
由于 WPF 是一个多线程系统,它必须执行后台操作,包括在多个线程之间进行同步。要返回主线程,它使用 Dispatcher您没有正确设置的基础设施。
要解决您的问题,您需要运行 WPF Dispatcher在 STA 线程上,而不是实现您自己的循环。
此外,为了完整性,链接到 related post这把我带到了这里。确保在设置调度程序基础架构后测量正确的内容。

关于WPF 窗口在程序终止之前不会释放其资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60692407/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com