【问题标题】:Unmanaged leak in a trivial WPF application普通 WPF 应用程序中的非托管泄漏
【发布时间】:2011-01-11 01:09:53
【问题描述】:

当鼠标移到我的 WPF 应用程序上时,我遇到了泄漏非托管内存的情况。具体来说,当我在 perfmon 或 Red Gate 的内存分析器中分析应用程序时,私有字节单调增加,但所有托管堆中的字节保持不变——我认为这意味着应用程序存在非托管泄漏。

我创建了一个简单的重现应用,但我看不出问题出在哪里。

该应用由一个包含四个项目的 ListView 组成。将鼠标快速移动到这些项目上会导致问题。

如果您有兴趣重现该问题,这里是代码——它不漂亮,但很简单。

谢谢


编辑:我为这个问题创建了一个Microsoft Connect issue


App.xaml

<Application x:Class="WpfLeakRepro.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Generic.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

App.xaml.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;

namespace WpfLeakRepro
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    }
}

Generic.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <LinearGradientBrush x:Key="ListItemHover"
                         EndPoint="0,1"
                         StartPoint="0,0">
        <GradientStop Color="Aqua"
                      Offset="0" />
        <GradientStop Color="White"
                      Offset="1" />
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="ListItemSelected"
                         EndPoint="0,1"
                         StartPoint="0,0">
        <GradientStop Color="Blue"
                      Offset="0" />
        <GradientStop Color="White"
                      Offset="1" />
    </LinearGradientBrush>
    <VisualBrush x:Key="CheckeredBackground"
                 Viewport="20,20,20,20"
                 ViewportUnits="Absolute"
                 TileMode="Tile"
                 Stretch="Fill">
        <VisualBrush.Visual>
            <Canvas Opacity="5">
                <Rectangle Fill="#FF606060"
                           Height="21"
                           Width="21"
                           Canvas.Top="20" />
                <Rectangle Fill="#FF606060"
                           Width="21"
                           Height="21"
                           Canvas.Left="20" />
                <Rectangle Fill="#FF646464"
                           Height="21"
                           Width="21"
                           Canvas.Left="20"
                           Canvas.Top="20" />
                <Rectangle Fill="#FF646464"
                           Width="21"
                           Height="21" />
            </Canvas>
        </VisualBrush.Visual>
    </VisualBrush>
    <Style TargetType="{x:Type ListViewItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListViewItem}">
                    <Border Background="{TemplateBinding Background}">
                        <Grid>
                            <GridViewRowPresenter />
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver"
                                 Value="true">
                            <Setter Property="Background"
                                    Value="{DynamicResource ListItemHover}" />
                        </Trigger>
                        <Trigger Property="IsSelected"
                                 Value="true">
                            <Setter Property="Background"
                                    Value="{DynamicResource ListItemSelected}" />
                        </Trigger>
                    </ControlTemplate.Triggers>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Window1.xaml

<Window x:Class="WpfLeakRepro.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="449" Width="497">
    <Grid>
        <ListView Margin="12"
                  Name="listView"
                  ItemsSource="{Binding}">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="File Name">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding Name}" />
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Thumbnail">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <Border Background="{DynamicResource CheckeredBackground}" Width="72" Height=48/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

Window1.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.IO;

namespace WpfLeakRepro
{
    public class Picture
    {
        public string Name { get; set; }
    }

    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            List<Picture> pictures = new List<Picture>();

            string[] images = new string[] {"Blue hills.jpg", "Sunset.jpg", "Water lilies.jpg", "Winter.jpg" };

            foreach (string imagePath in images)
            {
                pictures.Add(new Picture() { Name = imagePath });
            }

            DataContext = pictures;
        }
    }
}

【问题讨论】:

    标签: c# wpf memory-leaks


    【解决方案1】:

    该问题似乎与用于方格背景的VisualBrush 有关。将其替换为SolidColorBrush,问题就会消失。但这真的没关系:微软的人建议我安装 .NetFx 3.5sp1 的最新升级,这似乎解决了问题(更多细节here)。

    【讨论】:

      【解决方案2】:

      您可能在 WPF 绑定中创建了一个已知的内存泄漏,当绑定到未实现 INotifyPropertyChanged 的类的属性时可能会发生这种情况。在您的情况下,Picture 类的 Name 属性。

      解决方案是将绑定模式设置为 OneTime,让 Picture 实现 INotifyPropertyChanged 或将 Name 设置为依赖属性。

      ms supportthis blog post 了解更多信息。这些和其他已知的 WPF 内存泄漏可以在 here 找到。

      【讨论】:

      • 我不认为这是问题所在。 Picture 用于实现 INotifyPropertyChanged,但我将其删除以缩短我的 repro 应用程序。此外,如果这是问题所在,我相信泄漏将得到管理——数据绑定系统将保留它不应该引用的托管对象。 WPF 泄漏列表是一个很好的列表(我建议每个人都检查一下),但我已经查看了该列表,我认为只有 #2 适用,这就是你提到的问题,这似乎不是问题这里。老实说,我认为这个问题是一个新问题。
      猜你喜欢
      • 1970-01-01
      • 2012-01-30
      • 2020-07-11
      • 1970-01-01
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 2012-04-17
      相关资源
      最近更新 更多