WPF 视图泄漏 - 不可见,但仍呈现在后台
WPF View leak - invisible, but still rendered in the background
有一个复杂的App,我尽量简化场景。有一个主机 .exe (.NET),其中包含许多控件(ActiveX、.NET、WPF)。
一个控件基本上是一个包含项目的网格(称为 "list"),当出现新选择时,它会向另一个 WPF 控件(称为 "DataView")发送一条消息。 "DataView" 将显示当前选择 "list" 的详细信息。
当 DataView 收到该消息时,它将重新创建它的 ViewModel,并分配给它的 DataContext,因此重新创建它的视图。
它的View很复杂(声明XAML),全是控件,模板,还包含几个Images(类型:NonDPIImage,派生自Image,有一些基本的不重要的变化,就当作Image),它的源是一个转换器,它创建 BitmapImages。
<Image.Source>
<MultiBinding Converter="{StaticResource ImageConverter}">
...
它工作正常,但我注意到在选择更改后 "DataView" 更新变得越来越慢。
调试了一下,发现经过多次选择变化后,之前所有的View还在内存中,并且都在渲染它的内容,所以之前的所有View都会调用ImageConverter,所以越来越慢
我试过剖析,这是我经过10+次选择后看到的。
您看到之前的视图仍然在内存中(优先级较低的问题),图像和图像仍在渲染中(优先级较高的问题),使应用程序越来越慢。
我对 WPF 不是很熟悉,我是在泄漏后阅读的(主要是没有使用 DependencyProperty 或类似的),但是这个控件太难了,所以首先我想快速解决,所以防止渲染泄漏的视图,然后调查内存问题。 (当然两个最好...)
我试过在DataContext赋新值之前,将当前ViewImage.Source设置为null,所以至少泄漏的Image不会渲染自己,但是导致新视图 (!) 也丢失了它的 Image.Source,看起来 WPF 正在缓存或共享一些静态数据?
因为我的首要任务是停止 "invisible render",此后我尝试在创建新模型属性之前将一些模型属性设置为 null(因此它仍然会泄漏,但至少不再渲染), 因此当 Converter 将接收属性以创建图像时,将看到它为 null,并跳过渲染。
但它的行为很奇怪!
对于泄漏的实例,properties_get 代码中没有命中断点,就像 WPF 缓存值一样?
这阻止了我继续这条路。
任何帮助/想法将不胜感激。
你能 post 你的 ImageConverter 代码吗?
事情是从代码创建图像并将其作为 Image 对象的源,
可以在它们之间产生强大的 link 并且在像您这样的情况下会造成内存泄漏。
试试看这里:
我想我发现了问题:View HwndSource (AddHook()) 添加了一个消息挂钩,但没有被删除。这使整个视图(见红色矩形 class)保持活动状态。
现在,如果我在 UserControl_Unloaded 中调用 MyHwndSource.RemoveHook(WndProc),视图也将是 GCd。
有一个复杂的App,我尽量简化场景。有一个主机 .exe (.NET),其中包含许多控件(ActiveX、.NET、WPF)。
一个控件基本上是一个包含项目的网格(称为 "list"),当出现新选择时,它会向另一个 WPF 控件(称为 "DataView")发送一条消息。 "DataView" 将显示当前选择 "list" 的详细信息。
当 DataView 收到该消息时,它将重新创建它的 ViewModel,并分配给它的 DataContext,因此重新创建它的视图。
它的View很复杂(声明XAML),全是控件,模板,还包含几个Images(类型:NonDPIImage,派生自Image,有一些基本的不重要的变化,就当作Image),它的源是一个转换器,它创建 BitmapImages。
<Image.Source>
<MultiBinding Converter="{StaticResource ImageConverter}">
...
它工作正常,但我注意到在选择更改后 "DataView" 更新变得越来越慢。
调试了一下,发现经过多次选择变化后,之前所有的View还在内存中,并且都在渲染它的内容,所以之前的所有View都会调用ImageConverter,所以越来越慢
我试过剖析,这是我经过10+次选择后看到的。
您看到之前的视图仍然在内存中(优先级较低的问题),图像和图像仍在渲染中(优先级较高的问题),使应用程序越来越慢。
我对 WPF 不是很熟悉,我是在泄漏后阅读的(主要是没有使用 DependencyProperty 或类似的),但是这个控件太难了,所以首先我想快速解决,所以防止渲染泄漏的视图,然后调查内存问题。 (当然两个最好...)
我试过在DataContext赋新值之前,将当前ViewImage.Source设置为null,所以至少泄漏的Image不会渲染自己,但是导致新视图 (!) 也丢失了它的 Image.Source,看起来 WPF 正在缓存或共享一些静态数据?
因为我的首要任务是停止 "invisible render",此后我尝试在创建新模型属性之前将一些模型属性设置为 null(因此它仍然会泄漏,但至少不再渲染), 因此当 Converter 将接收属性以创建图像时,将看到它为 null,并跳过渲染。
但它的行为很奇怪!
对于泄漏的实例,properties_get 代码中没有命中断点,就像 WPF 缓存值一样?
这阻止了我继续这条路。
任何帮助/想法将不胜感激。
你能 post 你的 ImageConverter 代码吗? 事情是从代码创建图像并将其作为 Image 对象的源,
可以在它们之间产生强大的 link 并且在像您这样的情况下会造成内存泄漏。 试试看这里:
我想我发现了问题:View HwndSource (AddHook()) 添加了一个消息挂钩,但没有被删除。这使整个视图(见红色矩形 class)保持活动状态。 现在,如果我在 UserControl_Unloaded 中调用 MyHwndSource.RemoveHook(WndProc),视图也将是 GCd。