【问题标题】:WPF Memory LeakWPF 内存泄漏
【发布时间】:2011-02-21 02:28:49
【问题描述】:

我有一个我自己没有创建的 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>

【问题讨论】:

    标签: .net wpf performance memory-leaks


    【解决方案1】:

    当您试图在 .NET 应用程序中查找内存泄漏时,无论是否是 WPF,首先要看的是订阅事件的对象。

    如果对象 X 正在侦听对象 Y 引发的事件,则 Y 持有对 X 的引用。无论您实施何种虚拟化(或处置)方法,如果 X 不取消订阅 Y 的事件,X 将留在对象中与 Y 一样长的图形,并且永远不会被最终确定和垃圾收集。 (即使它实现了IDisposable 并且您在其上显式调用Dispose。)

    当您说“关闭表单没有帮助”时,这让我倍感怀疑:我希望有人在 Window 对象上实现了一个对象属性,并且该对象已经订阅了某种事件。所以你关闭了窗口,但它仍然存在于对象图中,因为它的属性之一正在被引用。

    (让您了解这可能是多么阴险:WinForms ToolStrip 控件在它们变得可见时订阅 Windows 主题更改事件。这非常棒,因为更改计算机的主题会自动反映在您的 UI 中正在运行的应用程序。如果在没有先将 Visible 设置为 false 的情况下取消引用 ToolStrip,它会继续接收主题更改事件,直到应用程序终止。)

    内存分析器可以帮助解决这个问题 - 这就是我发现我的应用程序在内存中有数千个 ToolStrip 对象的原因,尽管我认为它们都已被销毁。

    【讨论】:

    • +1:我公司的 WPF 应用程序每次生成新页面时都会泄漏数兆字节的内存,我们都认为这是 WPF 的错误。启动分析器,发现每个页面都连接到静态事件处理程序,但从未断开连接,导致灾难性(且易于修复)泄漏。
    【解决方案2】:

    “ElementFlow”控件与here 中描述的控件相同吗?控件似乎是already using virtualization,所以我不希望它访问不可见项的缩略图属性。

    您如何对公开“缩略图”属性的数据结构进行建模?您可以设置它以便属性在首次访问时按需加载缩略图吗?也许使用后备缓存(保持缩略图加载一段时间)来实现这一点可以解决这个问题。

    编辑

    我可能假设了一些我不应该拥有的东西。在阅读我链接的第二篇文章的 cmets 时,我现在认为可能是公开版本的 ElementFlow 控件实际上并没有实现虚拟化。也许您可以记录对“缩略图”属性的访问,并确定是否访问了不可见元素的属性。

    【讨论】:

    • 谢谢。我检查并可以验证 Thumbnail 属性被检索的次数与列表中的项目一样多。是的,这就是我正在使用的控件:)。听起来他发现了同样的事情。实现虚拟化有多难..? :)
    【解决方案3】:

    仅使用您的代码 sn-p 很难缩小问题范围。如果您还没有,您可能想Visual Profiler

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-05
      • 2011-03-19
      • 2011-08-12
      • 1970-01-01
      相关资源
      最近更新 更多