【问题标题】:Why doesn't my WPF application free up its memory?为什么我的 WPF 应用程序不释放它的内存?
【发布时间】:2021-08-08 18:45:42
【问题描述】:

我不明白为什么我的测试 WPF 应用程序在我关闭 MainWindow 并将其设置为 null 甚至运行垃圾收集器后没有释放它使用的内存?

一开始,甚至在创建 MainWindow 之前,应用程序几乎不占用内存,大约 5 MB,但是当我创建第一个窗口时,它占用了 43 MB,并且在应用程序的剩余生命周期中一直存在。难道不重新启动应用程序就可以再次将其恢复到 5 MB 吗?

Diagnostic Tools

public App()
{
    ShutdownMode = ShutdownMode.OnExplicitShutdown;

    DispatcherTimer dispatcherTimer = new DispatcherTimer();
    dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
    dispatcherTimer.Interval = new TimeSpan(0, 0, 2);

    Thread.Sleep(2000);
    dispatcherTimer.Start();
}

private void dispatcherTimer_Tick(object sender, EventArgs e)
{
    if (MainWindow == null)
    {
        MainWindow = new MainWindow();
        MainWindow.Show();
    }
    else
    {
        MainWindow.Close();
        MainWindow = null;

        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
    }
}

【问题讨论】:

  • WPF 和 .NET 框架决定何时收集某些对象,并且在某处进行了一些缓存。 GC.Collect 不是保证,即使您调用它两次。简而言之,这是您不应该担心的事情;垃圾收集器比你我聪明得多。
  • 内存被释放到操作系统有什么关系?
  • 对于 .NET 应用程序,测量内存使用情况的方法是使用性能监视器和 .NET 内存计数器。想想看。如果在应用程序运行时,内存系统分配了 43 meg 的虚拟内存并且 GC 运行,除非有原因,否则应用程序不会将其释放回操作系统 - 它可以一遍又一遍地重新分配相同的内存作为new 对象/GC 循环的一部分。
  • 应用程序在不使用时释放内存,而在主窗口关闭时释放内存是很正常的。问题是它针对更大的 WPF 应用程序进行了扩展,这就是我提出这个问题的原因。
  • 您的实际内存需求是多少?我使用的 WPF 应用程序在正常运行期间使用 1GB 和 4GB 之间,但它运行在普通 PC 设备上,而不是 Arduinos。

标签: c# wpf memory


【解决方案1】:

您有内存泄漏,因此GC 将无法收集您的MainWindow。您必须取消订阅您的事件处理程序。因此,将计时器保留在支持字段中:

MainWindow = null;
// Add this:
this.dispatcherTimer.Tick -= new EventHandler(dispatcherTimer_Tick);
this.dispatcherTimer.Stop();

【讨论】:

  • dispatcherTimer.Tick 持有事件委托,而不是 MainWindow。当dispatcherTimer_Tick 退出时,MainWindow 应该超出范围。
  • 它不会导致内存泄漏,您可以在没有 DispatcherTimer 的情况下进行相同的测试,只需打开并丢失 MainWindow 并将其设置为 null 将得到相同的结果。
  • 很公平。但是,您仍然有泄漏。更好地解决这个问题,以避免关于内存未释放的混淆。
猜你喜欢
  • 1970-01-01
  • 2011-05-26
  • 2015-06-14
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 2010-09-26
  • 2011-12-22
  • 1970-01-01
相关资源
最近更新 更多