我有一个我自己没有创建的WPF表单,所以我不擅长WPF。它虽然泄漏严重,但高达400 MB并且关闭表单无济于事。
问题在于我的应用程序一次加载所有图片。我想只加载那些可见的。这是大约300张图片,它们有点大,所以我的WPF格式可能会加载它们。
我有DataTemplate
我自己的类型,其属性为Thumbnail
。模板中的代码如下:
<Image Source="{Binding Path=Thumbnail}" Stretch="Fill"/>
然后我有一个控件的网格,上面的模板作为源。此控件的代码如下所示。请提供一些关于如何优化代码的提示,并且可能只获得可见的并且只能同时加载许多控件的提示?
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Controls:ElementFlow">
<Grid Background="{TemplateBinding Background}">
<Canvas x:Name="PART_HiddenPanel"
IsItemsHost="True"
Visibility="Hidden" />
<Viewport3D x:Name="PART_Viewport">
<!-- Camera -->
<Viewport3D.Camera>
<PerspectiveCamera FieldOfView="60"
Position="0,1,4"
LookDirection="0,-1,-4"
UpDirection="0,1,0" />
</Viewport3D.Camera>
<ContainerUIElement3D x:Name="PART_ModelContainer" />
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
<Viewport2DVisual3D
RenderOptions.CachingHint="Cache"
RenderOptions.CacheInvalidationThresholdMaximum="2"
RenderOptions.CacheInvalidationThresholdMinimum="0.5"/>
</Viewport3D>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
答案 0 :(得分:4)
当您尝试在.NET应用程序(无论是否为WPF)中查找内存泄漏时,首先要查看订阅事件的对象。
如果对象X正在侦听由对象Y引发的事件,那么Y保存对X的引用。无论您实现什么虚拟化(或处置)方法,如果X没有取消订阅Y的事件,X将保留在对象中图表只要是Y,并且永远不会最终确定并进行垃圾收集。 (即使它实现了IDisposable
,你明确地在其上调用Dispose
。)
当你说“关闭表单没有帮助”时,这让我倍加怀疑:我希望有人在Window
对象上实现了一个对象属性,并且该对象已经订阅了一些事件类。因此,您关闭窗口,但它仍然存在于对象图中,因为正在引用其中一个属性。
(为了让您知道这可能是多么阴险:WinForms ToolStrip
控件在它们变得可见时订阅Windows主题更改事件。这非常棒,因为更改计算机主题会自动反映在UI中如果你在没有先将ToolStrip
设置为false的情况下取消引用Visible
,它就会继续接收主题更改事件,直到应用程序终止为止。
内存分析器可以帮助解决这个问题 - 这就是我发现我的应用程序在内存中有数千个ToolStrip
对象的方式,即使我认为它们都被破坏了。
答案 1 :(得分:2)
'ElementFlow'控件是否与here描述的控件相同?控件似乎是already using virtualization,所以我不希望它访问不可见项目的Thumbnail属性。
如何对暴露“缩略图”属性的数据结构进行建模?你可以设置它,以便属性需要在首次访问时加载缩略图吗?也许使用后备缓存(将缩略图加载一段时间)来实现这一点可以解决问题。
修改强>
我可能已经假设了一些我不应该拥有的东西。在阅读我链接的第二篇文章的评论时,我现在认为可能是公开提供的ElementFlow控件版本实际上并未实现虚拟化。也许您可以记录对“缩略图”属性的访问,并确定是否访问了不可见元素的属性。
答案 2 :(得分:0)
仅使用您的代码段很难缩小问题范围。如果您还没有,可能需要Visual Profiler。