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 unSolidColorBrush
il cuiColor
è 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.
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
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