我们正在运行一个不会释放内存的大型WPF应用程序.它不是真正的内存泄漏,因为内存将最终被释放.我知道通常情况下,这不会被认为是一个问题.不幸的是,它与WPF命令基础结构一起成为一个性能问题.有关详细信息,请参见下文.
发现
我们有自动测试,可以执行典型的用例.有些情况正常,正在及时释放记忆.其他人正在占用内存,直到客户端被最小化,打开了一个新的窗口或者触发Gen2集合的其他一些条件.
•使用ANTS,我们看到,对象没有GC根,但是对其他需要完成的对象的引用很多.
•WinDbg没有显示任何对象准备好完成.
•运行几个GC.Collect(),GC.WaitForPendingFinalizers()完全释放内存.
•我们知道哪个UI操作会导致高内存条件,但是我们无法识别任何可疑的代码.
题
我们非常感谢任何关于调试这个问题的建议.
WPF CommandManager背景
WPF CommandManager包含用于提升CanExecuteChanged事件的WeakReferences(_requerySuggestedHandlers)的私有集合.处理CanExecuteChanged是非常昂贵的(特别是找到CanExecute的EventRoute,这显然是一个RoutedEvent).每当CommandManager感觉如果可以执行命令时,它会重新查询,它会遍历此集合并调用相应命令源上的CanExecuteChanged事件.
只要有引用对象的GC句柄,WeakReferences不会从该集合中删除.当对象尚未被收集时,CommandHelper会继续处理这些元素(ButtonBase或MenuItems)的CanExecute事件.如果有很多垃圾(在我们的情况下),这可能会导致非常大量的调用CanExecute事件处理程序,这导致应用程序真的滞后.