Domanda

Aggiornamento:Ho provato questo su un altro, più correttamente installato, macchina.Io non riuscivo a riprodurre questo su quella macchina.Se trovo quello che offendere (VSStudio) componente causa di questo, vi farò sapere.

Ho creato alcuni Uielement dal codice dietro e stava scontando la procedura di garbage collection di chiara roba.Tuttavia, gli oggetti non sono libero ed il tempo che mi aspettavo.Mi aspettavo loro di essere freeed a RemoveAt(0), ma sono liberata solo alla fine del programma.

Come posso rendere gli oggetti essere liberato quando viene rimosso dalla collezione di Tela?

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
    MouseDown="Window_MouseDown">
  <Grid>
    <Canvas x:Name="main" />
  </Grid>
</Window>

Il codice è:

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

private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
  GC.Collect(); // This should pick up the control removed at a previous MouseDown
  GC.WaitForPendingFinalizers(); // Doesn't help either

  if (main.Children.Count == 0)
    main.Children.Add(new MyControl() { Background = Brushes.Yellow, Width = 100, Height = 50 });
  else
    main.Children.RemoveAt(0);
 }
}

public class MyControl : UserControl
{
  ~MyControl()
  {
    Debug.WriteLine("Goodbye");
  }
}

Nessuna soluzione corretta

Altri suggerimenti

Cambia

public class MyControl : UserControl

a

public class MyControl : ContentControl

e sarà dire addio (dopo la seconda volta si rimuove il controllo.) Ho anche verificato la memoria non perde utilizzando

Debug.WriteLine("mem: " + GC.GetTotalMemory(true).ToString());

Inoltre, vedere questo :

  

Si rimuove il TestControl deselezionando grid.Children, ma non è immediatamente per la garbage collection. Diverse operazioni asincrone su di essa sono in corso, e non può essere GC'd finché tali operazioni complete (questi includono la generazione dell'evento a vuoto e un po 'il codice di pulitura nel motore di rendering).

     

ho verificato che se si aspetta fino a quando queste operazioni complete (ad esempio programmando un'operazione di Dispatcher con priorità ContextIdle), il TestControl diventa ammissibile per GC, indipendentemente dalla presenza di un vincolante per la TextBlock.

UserControl deve o avere un evento interno che non ripulire in fretta, o potrebbe essere un bug con VS2010 RC. Mi piacerebbe segnalo questo attraverso Connect, ma per ora passare a ContentControl.

Dal momento che si sta utilizzando UserControl, presumo si dovrà anche passare a utilizzando il modello generic.xaml. Che non è troppo difficile di un cambiamento-over (e per la maggior parte delle cose è una soluzione migliore.)

Gli oggetti in C # non sono automaticamente "liberato" non appena essi non sono più utilizzati.

Al contrario, quando si rimuove l'oggetto dal vostro controllo, diventa per la garbage collection , a quel punto, a patto di avere altri riferimenti a tale UIElement.

Una volta che un oggetto è "senza radici" (non ci sono riferimenti, direttamente o indirettamente, da qualsiasi oggetto utilizzato nell'applicazione), diventa idoneo per la raccolta. Il garbage collector poi, alla fine, ripulire l'oggetto, ma quando questo accade non è qualcosa che (in genere) di controllo.

Proprio la fiducia che alla fine ottenere ripulito. Questa è la bellezza di C # (e .NET in generale) -. La gestione, e la preoccupazione, di questo viene gestito per voi


Edit: Dopo alcuni test, sembra che la finestra contiene un riferimento alla UIElement fino al prossimo passaggio di layout. È possibile forzare ciò avvenga con l'aggiunta di una chiamata a:

this.UpdateLayout();

Dopo aver rimosso l'elemento (s) dalla tela Children. Questo farà sì che gli oggetti siano disponibili per GC.

Ci sono 3 generazioni di raccolta dei rifiuti in C #, quindi, anche se non ci sono riferimenti a oggetti, si potrebbe prendere 3 garbage collection per liberarli.

È possibile utilizzare il GC.Collect () 's parametro per forzare una garbage collection 3 ° generazione,
Tuttavia, la migliore approuch è di non chiamare GC.Collect () voi stessi,
invece utilizzare l'interfaccia IDisposable e si legano i bambini a un ObservableCollection e quando si ottiene un evento CollectionChanged Dispose () di tutti gli oggetti rimossi.

Si possono trovare questo tipo di interesse.Ho scoperto di recente che x:Name estensione di markup memorizza un riferimento per il UIElement nel controllo parentale in un dizionario utilizzando come chiave il nome di stringa.

Quando si rimuove il UIElement dal suo genitore, il dizionario mantiene un riferimento al controllo.

C'è un post di un blog / video di debug la perdita di memoria qui: WPF x:Name Perdita di Memoria

La soluzione è non usare x:Nome o per garantire che i controlli che vengono tenuti in vita da x:Nome vengono cancellati, così da non consumare troppa memoria prima di una sezione di visual tree sono stati raccolti.

Aggiornamento: Si annullare la registrazione di un nome di classe utilizzando il NameScope

this.grid.Children.Remove(child); // Remove the child from visual tree
NameScope.GetNameScope(this).UnregisterName("child"); // remove the keyed name
this.child = null; // null the field

// Finally it is free to be collected! 

Abbiamo avuto lo stesso problema e anche pensato che questo può essere il motivo. Ma abbiamo analizzato il nostro progetto utilizzando strumenti Memory Profiler e scoperto che non c'è niente a che fare con la Grid.Remove o Grid.RemoveAt. Quindi penso che il mio suggerimento è solo dare uno sguardo al vostro progetto lo strumento profiler di memoria e vedere ciò che sta accadendo all'interno del vostro progetto. spera che questo aiuti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top