代码之家  ›  专栏  ›  技术社区  ›  IV.

普通WPF应用程序中的非托管泄漏

  •  7
  • IV.  · 技术社区  · 15 年前

    当鼠标移到我的WPF应用程序上时,我遇到了一种情况,我正在泄漏未管理的内存。具体来说,当我在 perfmon 或者红门的内存分析器,私有字节单调地增加,但是所有托管堆中的字节保持不变——我相信,这意味着应用程序有一个非托管的泄漏。

    我已经创建了一个简单的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>
    

    代码文件

    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
        {
        }
    }
    

    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>
    

    Windows 1.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>
    

    Windows 1.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 回复  |  直到 14 年前
        1
  •  7
  •   Lars Truijens    15 年前

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

    解决方案正在将绑定模式设置为一次性,使 图片 实施 InotifyProperty已更改 或制造 名字 成为依赖属性。

    阅读更多关于它的信息 ms support this blog post . 可以找到这些和其他已知的WPF内存泄漏 here .

        2
  •  1
  •   IV.    14 年前

    这个问题似乎与 VisualBrush 它被用于方格背景。将此替换为 SolidColorBrush 然后问题就消失了。但实际上并不重要:微软的人建议我安装.netfx 3.5sp1的最新升级,这似乎可以解决问题(更多详细信息 here )