2010-01-29 10 views
7

Me he encontrado con una situación en la que goteo la memoria no administrada cuando el mouse se mueve sobre mi aplicación WPF. Específicamente, cuando perfilo la aplicación en perfmon o el perfilador de memoria de Red Gate, los bytes privados aumentan monótonamente, pero los bytes en todos los montones administrados se mantienen constantes, lo que, creo, significa que la aplicación tiene una fuga no administrada.Fuga no administrada en una aplicación WPF trivial

He creado una aplicación de reproducción trivial, pero no puedo ver dónde está el problema.

La aplicación consiste en un ListView con cuatro elementos. Mover el mouse rápidamente sobre estos elementos causa el problema.

Aquí está el código si está interesado en reproducir el problema: no es bonito, pero es simple.

Gracias


edición: He creado un Microsoft Connect issue para este problema.


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

Respuesta

1

El problema parece tener algo que ver con el VisualBrush que se estaba utilizando para el fondo a cuadros. Reemplace esto con un SolidColorBrush, y el problema desaparece. Pero realmente no importa: la gente de Microsoft sugirió que instale las últimas actualizaciones de .NetFx 3.5sp1, y esto parece solucionar el problema (más detalles here).

6

Es posible que haya creado una pérdida de memoria conocido en enlaces WPF que pudiera ocurrir cuando se une a las propiedades de las clases no implementando INotifyPropertyChanged. En su caso, la propiedad Name de la clase Picture.

Las soluciones están configurando el Modo vinculante en OneTime, permitiendo que Picture implemente INotifyPropertyChanged o establezca Name en una propiedad de dependencia.

Más información al respecto desde ms support y this blog post. Estas y otras fugas de memoria conocidas de WPF pueden encontrarse en here.

+0

No creo que este sea el problema. 'Picture' solía implementar' INotifyPropertyChanged', pero lo eliminé para acortar mi aplicación de reproducción.Además, si este fuera el problema, creo que se gestionaría la fuga: el sistema de enlace de datos mantendría las referencias de objetos administrados que no debería. La lista de filtraciones de WPF es buena (y recomiendo que todos la revisen), pero revisé esa lista, y creo que solo se aplica el número 2 y ese es el problema que mencionaste, que no parece ser el problema aquí. Honestamente creo que este problema es nuevo. –

Cuestiones relacionadas