【问题标题】:WPF Window.Close memory leakWPF Window.Close 内存泄漏
【发布时间】:2011-08-12 12:52:26
【问题描述】:

警告:这是我的第一个“真正的”WPF 应用程序。我确定这是我在某个地方遇到的逻辑错误,但不知道我应该在哪里寻找。

我有一个自助服务终端类型的应用程序,它在各种窗口中循环,每个窗口显示不同类型的数据。我(目前)通过计时器控制这些,并且应用程序运行良好,直到我最终遇到内存不足异常。

我在窗口中旋转的代码如下:

private Window activeWindow;

private void ShowNextTaskWindow(ITask task) {

    Window nextWindow = windowManager.GetWindowForTask(task);

    nextWindow.Show();

    if (activeWindow != null) {
        activeWindow.Close();
    }
    activeWindow = nextWindow;

}

windowManager 类仅根据任务类型实例化适当类型的窗口——即 NewsWindow 或 VideoWindow:

public Window GetWindowForTask(ITask task) {

    Window taskWindow = null;

    switch (task.TaskType) {
            case TaskType.Web:
                taskWindow = new WebWindow(task as WebTask);
                break;

            case TaskType.Rss:
                taskWindow = new RssWindow(task as RssTask);
                break;

     ..... etc ......

    }
    return taskWindow;
}

每个窗口确实(仅)在构造函数中添加了一个事件处理程序,如下所示:

 Loaded += new RoutedEventHandler(Window_Loaded);

当然,还有一个称为 Window_Loaded 的适当方法可以完成一些布局工作(设置窗口大小、控件大小等)。

我遇到的问题是,应用程序只是继续消耗内存,直到它最终因内存不足异常而崩溃——而且我似乎无法弄清楚我遗漏了什么。

据我了解,调用 Window.Close() 应该摆脱窗口,所以我不知道该去哪里寻找问题。

有什么想法吗?

【问题讨论】:

  • 您确定不是窗口中泄漏内存的控件之一吗?如果您使用空窗口运行应用程序,是否会发生 Out Of Memory 异常?
  • 您的窗口是否包含非托管资源?考虑使用 MVVM 设计模式 - 您当前的架构不是 WPF 风格的。
  • 很像对stackoverflow.com/questions/2860965/wpf-memory-leak 的回答,我发现了一个案例,其中我确实有一个未正确处理的订阅者事件处理程序。我已经解决了这个问题——但总的来说,仍然遇到同样的问题。将研究 MVVM,因为我知道我“做错了”。谢谢,@Danny Varod
  • 已修复。有一个事件处理程序没有被删除。无论如何,现在完全抛弃并用 MVVM 编写。

标签: .net wpf memory-leaks


【解决方案1】:

当您在 nextWindow 上调用 .Show() 时,它会导致 activeWindow 不可见,因此当您调用 Close() 时,activeWindow 不会释放它的控件。

Close() 文档在备注部分明确提到了这种情况: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx

【讨论】:

  • 您的链接指的是winforms,而OP使用WPF窗口不确定WPF窗口是否遇到同样的问题。
【解决方案2】:

要找到“泄漏”,您必须先进行一些分析。

  1. 通过测试程序并仅使用一种类型的窗口来查找导致泄漏的窗口。让程序运行直到它失败或者您确定此窗口类型不会导致任何问题。对所有类型重复此操作。
  2. 找到有问题的 Window 类型后,检查它们的代码并一一关闭/打开功能以找到问题。

【讨论】:

  • 我看到了所有窗口类型的行为——它不限于一个。
【解决方案3】:

您真的应该使用CLR Profiler 找出哪些对象正在泄漏并消除泄漏源...

但我还建议,假设您正在循环执行少量 ITask,重用您的 Window 实例可能是个好主意。在您的GetWindowForTask 中,您可以使用字典(可能是ConditionalWeakTable)将Windows 与任务相关联。如果 Task 已经有一个 Window,则直接返回它,不要实例化一个新的。

根据实际发生的情况,重用 Windows 可能会“阻止泄漏”(尽管您可能仍然应该弄清楚并以正确的方式解决它)。

【讨论】:

  • 是的,我支持你。目前正在重写为 MVVM,目的是尽可能地重用。但是,没有使用该工具,将在正在运行的应用程序上尝试。谢谢!
猜你喜欢
  • 2011-02-21
  • 1970-01-01
  • 2010-12-05
  • 2011-03-19
  • 1970-01-01
相关资源
最近更新 更多