WPF GarbageCollection中的高级调试建议

时间:2012-11-26 15:39:11

标签: c# wpf garbage-collection finalizer memory-profiling

场合

我们正在运行一个大型WPF应用程序,它不会释放内存很长一段时间。它不是真正的内存泄漏,因为内存最终会被释放。我知道通常情况下,这不会被认为是一个问题。不幸的是,它与WPF指挥基础设施相结合成为一个性能问题。请参阅下文以获取更详细的说明。

首饰

我们有自动化测试,可以执行典型的用例。有些案例工作正常,并及时释放记忆。其他人正在占用内存,直到客户端最小化,打开一个新窗口或触发Gen2集合的其他一些条件。

•使用ANTS我们看到,对象没有GC Root,但是很多引用需要完成的其他对象。

•WinDbg没有显示任何准备完成的对象。

•运行多个GC.Collect()GC.WaitForPendingFinalizers()完全释放内存。

•我们知道哪种UI操作会导致高内存条件,但我们无法识别任何可疑代码。

问题

我们非常感谢有关调试此类问题的任何建议。


WPF CommandManager背景

WPF CommandManager保存WeakReferences(_requerySuggestedHandlers)的私有集合,用于引发CanExecuteChanged事件。处理CanExecuteChanged非常昂贵(特别是找到CanExecute的EventRoute,显然是RoutedEvent)。只要CommandManager感觉像是在执行命令就可以重新查询,它会遍历此集合并在相应的命令源上调用CanExecuteChanged事件。

只要存在引用对象的GC句柄,就不会从该集合中删除WeakReferences。虽然尚未收集该对象,但CommandHelper会继续处理这些元素的CanExecute事件(ButtonBase或MenuItems)。如果有大量垃圾(如我们的情况),这可能会导致CanExecute事件处理程序的调用数量极大,导致应用程序非常滞后。

2 个答案:

答案 0 :(得分:2)

我的一个应用程序遇到了同样的问题。在窗口的每个开口处,我打电话:

GC.GetTotalMemory(true);

这将迫使GC立即清理内存而无需等待。您可以在此处详细了解此方法:

http://msdn.microsoft.com/en-us/library/system.gc.gettotalmemory.aspx

关于调用CanExecute的问题,我试图避免它们,因为性能问题相同。相反,我在视图模型中使用属性,并将可视元素的 IsEnabled 属性从XAML绑定到视图模型中的属性。通过这种方式,整体性能得到改善,CanExecute调用也消失了。

我希望这会有所帮助。

答案 1 :(得分:0)

尝试使用CLRProfiler,这是downloading link。它显示了分配,处理和存活的事件处理程序。我相信您可以使用此工具追踪根本原因。 “高级.NET调试”一书列出了一些很好的调试工具,您可以阅读它以获得一些帮助。