场合
我们正在运行一个大型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事件处理程序的调用数量极大,导致应用程序非常滞后。
答案 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调试”一书列出了一些很好的调试工具,您可以阅读它以获得一些帮助。