一个简单的WPF应用程序中的非托管泄漏

时间:2010-01-29 21:57:18

标签: c# wpf memory-leaks

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

我创建了一个简单的repro应用程序,但我看不出问题所在。

该应用程序包含一个包含四个项目的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;
        }
    }
}

2 个答案:

答案 0 :(得分:8)

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

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

ms supportthis blog post了解详情。可以找到这些和其他已知的WPF内存泄漏here

答案 1 :(得分:1)

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