如何强制窗口的垃圾收集?

时间:2012-06-25 01:48:23

标签: wpf memory-leaks

我试图通过对一个对象保持额外的弱引用来主动确保我不会导致代码中的内存泄漏,并且当它应该被释放时检查它不再是活动的(这是条件代码所以它只是在我测试时运行。)

要简单地重现我看到的效果,请创建一个新的WPF应用程序并在主窗口上放置一个Button。创建另一个窗口,并在其上放置一个TextBox。在按钮的单击处理程序中,输入以下代码:

  Window1 w = new Window1();
  WeakReference weak = new WeakReference(w);
  w.ShowDialog();
  w = null;
  // Equivalent to Application.DoEvents() just in case...
  Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
  GC.Collect();
  GC.WaitForPendingFinalizers();
  if (weak.Target != null)
    MessageBox.Show("Memory Leak");

当你运行它时,点击按钮,当窗口显示时,只需点击'x'关闭它,没有任何反应 - 一切都很好。现在做同样的事情,但是当窗口显示时,单击TextBox然后单击'x'。我每次都收到“Memory Leak”消息。

Ants Profiler显示System.Windows.Documents.TextEditor具有对TextBox的引用(可能仅在您关注TextBox时才设置),并且TextBox具有对该窗口的引用。它不是真正的内存泄漏,因为如果您多次执行该过程,则会收集以前的窗口,而不是最新的窗口。但是,这意味着我无法编写确认内存没有泄漏的测试。

我是唯一想要这种保证水平的人,还是有另一种方式?

4 个答案:

答案 0 :(得分:2)

我认为有些人错过了你的问题。你不是试图强迫GC的手,而是先发制人地发现任何内存泄漏,为此我为你鼓掌。

在这种特殊情况下,似乎TextEditorinternal)正在添加事件处理程序,并且在检查运行时尚未分离。你有没有试过在抽水调度员之前明确地将焦点移出关闭的窗口?

如果您尝试在您的应用程序中正确地执行这些测试,而不是在集成测试的更受控制的环境中,我认为您将继续遇到这类问题,因此您可能需要重新考虑您的方法。 / p>

答案 1 :(得分:0)

如果收集了以前的实例,则不是内存泄漏。垃圾收集器并不总是采用最新的项目,而是设计的。如果你试图猜测它,你可能会遇到问题。

在真实的内存泄漏中,物品会累积而不会被回收。使用分析器可以最好地检测到这一点。

答案 2 :(得分:0)

Windows不仅由您的代码管理,还由某些WPF类(如Application)管理。调用Collect并不保证或证明任何内容,最终会收集窗口。

答案 3 :(得分:0)

尝试使用DispatcherPriority。 ContextIdle

Dispatcher.CurrentDispatcher.Invoke( DispatcherPriority.ContextIdle, new System.Action(delegate { }));