WPF GarbageCollection中的高级调试建议

el-*_*ino 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成本非常高(尤其是找到EventRoute CanExecute,显然是一个RoutedEvent).只要CommandManager感觉像是在执行命令就可以执行,它会遍历此集合并CanExecuteChanged在相应的命令源上调用事件.

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

Ale*_*icu 5

我的一个应用程序也有同样的问题。每次打开窗口时我都会调用:

GC.GetTotalMemory(true);
Run Code Online (Sandbox Code Playgroud)

这将强制 GC 立即清理内存,而无需等待。您可以在此处阅读有关此方法的更多信息:

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

关于调用 CanExecute 的问题,我尝试避免它们,因为同样的性能问题。相反,我在视图模型中使用属性,并将XAML 中的可视元素的IsEnabled属性绑定到视图模型中的属性。这样整体性能就提升了,CanExecute调用也没有了。

我希望这个能帮上忙。