2015-07-30 9 views
6

Utilizzando .NET 4.0 aggiornato, ho trovato una strana perdita di memoria che può essere riprodotta seguendo il codice di esempio.Border.Effect binding memory leak ma Border.Background non è

  • app.xml ha alcune risorse a livello di applicazione che si associano alle proprietà in app.xml.cs. La risorsa che crea una perdita è una <DropShadowEffect> la cui proprietà di dipendenza è associata a una proprietà nell'oggetto App.
  • Nella finestra principale è presente un pulsante per avviare una finestra delle perdite in cui vengono utilizzate le risorse definite in app.xml.
  • Quando la finestra di perdita viene chiusa, non è raccolta dati inutili. Questo si verifica solo se la finestra di perdita utilizza la risorsa DropShadowEffect sopra menzionata. Non si verifica su un SolidColorBrush il cui Color è inoltre associato alla stessa origine.

davvero apprezzare se qualcuno mi può dire perché questa perdita avviene sul DropShadowEffect ma non sul SolidColorBrush?

app.xml

<Application x:Class="WpfSimple.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Application.Resources> 
     <!--this one make GC unable to collect LeakWindow--> 
     <DropShadowEffect x:Key="AppDropShadowColor" 
       Color="{Binding Source={x:Static Application.Current}, Path=DropShadowColor, Mode=OneWay}" /> 
     <!--this one does not leak--> 
     <SolidColorBrush x:Key="AppBackground" 
       Color="{Binding Source={x:Static Application.Current}, Path=DropShadowColor, Mode=OneWay}" /> 
    </Application.Resources> 
</Application> 

App.xml.cs Iniziamo MainWindow e implementa INotifyPropertyChanged per la proprietà DropShadowColor.

public partial class App : Application, INotifyPropertyChanged 
    { 
     protected override void OnStartup(StartupEventArgs e) 
     { 
      base.OnStartup(e);   
      // start main window 
      var mainWindow = new MainWindow(); 
      mainWindow.Show(); 
     } 

     private Color _dropShadowColor = Colors.Blue;  
     public Color DropShadowColor 
     { 
      get { return _dropShadowColor; }  
      set { 
       _dropShadowColor = value; 
       OnPropertyChanged("DropShadowColor"); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } 
     } 
    } 

MainWindow.xml e MainWindow.xml.cs ha un pulsante per creare un LeakWindow, mostrato sotto.

var win = new LeakWindow {Owner = this}; 
win.Show(); 

C'è anche un altro pulsante da eseguire GC.Collect();

LeakWindow.xml

<Window x:Class="WpfSimple.LeakWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Leak" Height="300" Width="300"> 
    <Grid> 
    <!--leak--> 
    <Border Width="200" Height="200" BorderThickness="1" BorderBrush="Black" Effect="{StaticResource AppDropShadowColor}"/> 

    <!--no leak if comment out above and uncomment below--> 
    <!--<Border Width="200" Height="200" BorderThickness="1" BorderBrush="Black" Background="{StaticResource AppBackground}"/>--> 
    </Grid> 
</Window> 

LeakWindow.xml.cs

public partial class LeakWindow : Window 
    { 
     public LeakWindow() 
     { 
      InitializeComponent(); 
     }  

     ~LeakWindow() 
     { 
      Debug.WriteLine("LeakWindow finalized"); 
     } 
    } 

Aggiornamento

  • La mia ricerca mostra questo potrebbe essere correlato al DynamicResource\StaticResource cause memory leaks. Ma questo è stato corretto all'inizio di .NET 3.5 (kb967328). Ho anche provato il metodo WalkDictionary menzionato in quella discussione ma nessun aiuto.
  • La modifica della modalità di binding su OneTime non è di aiuto.
  • Passare a .NET 4.5 (anche aggiornato per data) e utilizzare DynamicResource non aiuta.

Ulteriori analisi mostra la perdita è causata da un riferimento EventHandler da DropShadowEffect a Border.Effect. Probabilmente una notifica di modifica dovuta al binding in DropShadowEffect.
Ancora, che strano è Perché ciò si verifica solo su ma non su Border.Background?

Workground
Aggiunta x:Shared=false a <DropShadowEffect> in app.xml può risolvere questo. Ora posso disporre di risorse definite sull'applicazione ma perdere l'efficienza della memoria.

risposta

1

Penso che il problema sia causato dal modo in cui 10 è collegato all'albero visivo. Spostando il DropShadowEffect nei vostri modelli di controllo invece di avere come risorsa potrebbe risolvere la falla, ma poi si perderebbe avere quella risorsa condivisa ...

+0

grazie Glen, 'x: static' non spiega perché' DropShadowEffect' perde ma 'SolidColorBrush' no. Ho provato 'Mode = OneTime' su' DropShadowEffect', e sorprendentemente ci sono ancora perdite. Aggiornerò questi risultati – Peter

+0

grazie Glen per l'aggiornamento. Sì, sei corretto (upvoted). Ciò che mi dà fastidio è il motivo per cui 'Border.Background' non perde mentre' Border.Effect' fa? – Peter

0
 <Controls:MetroWindow x:Class="WpfApplication.Window" 
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" 
    ShowMaxRestoreButton="False" 
     ResizeMode="NoResize" ShowMinButton="False" 
     EnableDWMDropShadow="True" WindowStartupLocation="CenterScreen" Name="Window" 
Height="400" Width="567"> 

u può provare a importare applicazioni mah finestra ombra ha con una riga EnableDWMDropShadow = "True"

+0

MahApps sembra carino anche se non lo vedo correlato alla mia domanda. – Peter