2013-08-30 11 views
34

Devo separare gli articoli quando l'oggetto scompare per evitare perdite di memoria? Immagino di essere solo un po 'preoccupato che, se ricarico e venga applicato un nuovo modello a un controllo, e in quel modello esista un vincolo a un elemento esterno, ciò potrebbe impedire che il controllo effettuato per il modello venga eliminato dalla garbage collection?I binding possono creare perdite di memoria in WPF?

risposta

55

Se non si esegue il binding a DependencyProperty o un oggetto che implementa INotifyPropertyChanged, la rilegatura può perdere memoria e si dovrà separare quando si è terminato.

Questo perché se l'oggetto non è un DependencyProperty o non implementa INotifyPropertyChanged allora utilizzato l'evento ValueChanged tramite il metodo PropertyDescriptorsAddValueChanged. Ciò fa sì che CLR crei un riferimento forte da PropertyDescriptor a object e nella maggior parte dei casi il CLR manterrà un riferimento a PropertyDescriptor in una tabella globale.

Poiché l'associazione deve continuare ad ascoltare le modifiche. Questo comportamento mantiene vivo il riferimento tra PropertyDescriptor e object mentre il target rimane in uso. Ciò può causare una perdita di memoria nello object e in qualsiasi object a cui fa riferimento object. Ciò include la destinazione di associazione dati.

Così, in breve, se si sono vincolanti a un oggetto DependencyProperty o INotifyPropertyChanged allora si dovrebbe essere ok, altrimenti come ogni evento sottoscritto si dovrebbe annullare le associazioni


Edit: c'è una possibilità questa è stato risolto in .NET4.5 usando Debole Eventi/Riferimenti, ma dopo alcuni test rapidi mi è sembrato lo stesso, dovrò immergermi più profondamente per confermare, quindi dirò personalmente in potrebbe essere risolto in 4.5 :)

+1

Questa è una risposta molto migliore - Ho imparato un bel po 'qui – jdphenix

+0

@ sa_ddam213: sia il DP che INotifyPropertyChanged sono sicuri. Ad ogni modo, sei sicuro del PD? Intendo dire che le cose dovrebbero essere andate bene nell'ultimo framework .Net 4.5, in cui il pattern WeakEvent è usato intensamente. –

+0

Ho appena controllato due volte con .NET4.5 e sembra ancora che si verifichi una perdita quando si usa PropertyDescriptor, Se vuoi confermare ho usato la fuga di Jossef Goldberg testata per WPF e ricompilata a 4.5, link: http: //blogs.msdn.com /b/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx, non ho testato molto nelle perdite in 4.5 come le perdite nei binding nelle precedenti versioni del framework ho cambiato le mie abitudini di codifica WPF in modo permanente per evitare il problema :), spero sia corretto e aggiungerò la clausola di esclusione di responsabilità di cui sopra 4.5 –

6

A partire da http://msdn.microsoft.com/en-us/library/aa970850.aspx, WPF utilizza i modelli di evento deboli, che non contengono forti riferimenti agli oggetti e consentono loro di essere sottoposti a GC se sono gli unici riferimenti a un oggetto.

"Molti aspetti del binding dei dati WPF hanno già il pattern di evento debole applicato nel modo in cui gli eventi vengono implementati."

+1

eventi deboli vengono utilizzati solo su '' DependencyProperties' e oggetto INotifyPropertyChanged', quindi se si sono vincolanti per un POCO con una modalità di legame diverso da 'OneTime' si potrebbe finire up leak memory –

6

Non fingere di rispondere, solo per riferimento. In un articolo classico su Finding Memory Leaks in WPF-based applications autore Jossef Goldberg, descritto in casi di dettaglio, dove potrebbe esserci una perdita di memoria nell'applicazione WPF. In realtà, la maggior parte si riferisce a .NET 3.5/4.0, ma alcuni casi potrebbero essere rilevanti fino ad oggi. Inoltre, avere un piccolo extension.

Citazione circa perdita nel Binding:

Cause:

Questa perdita documentato in questo kb article. Viene attivato perché:

Il controllo TextBlock ha un binding a un oggetto (myGrid) che ha un riferimento indietro allo TextBlock (è uno dei bambini di myGrid).

Note: che questo tipo di perdita di DataBinding è univoco per uno scenario specifico (e non per tutti gli scenari DataBinding) come documentato nello kb article. La proprietà nel Path non è un DependencyProperty e non in una classe che implementa INotifyPropertyChanged e inoltre deve esistere una catena di forti riverenze.

Codice:

myDataBinding = new Binding("Children.Count"); 
myDataBinding.Source = myGrid; 
myDataBinding.Mode = BindingMode.OneWay; 
MyTextBlock.SetBinding(TextBlock.TextProperty, myDataBinding); 

codice che perde lo stesso può essere scritto anche in XAML:

<TextBlock Name="MyTextBlock" 
      Text="{Binding ElementName=myGrid, Path=Children.Count}" /> 

Fix/Workaround:

ci sono pochi di approcci, la più facile è semplicemente quello di cancellare il legame quando le finestre stanno per chiudersi.

es .:

BindingOperations.ClearBinding(MyTextBlock, TextBlock.TextProperty); 

altro approccio è quello di impostare la modalità di associazione dei dati OneTime. Vedi lo kb article per altre idee.

Link utile:

Avoiding a WPF memory leak with DataBinding