Question

Mise à jour : J'ai essayé sur un autre, plus proprement installé, machine. Je ne pouvais pas reproduire cela sur cette machine. Si je trouve ce que le composant incriminé (VSStudio) provoque, je vous le ferai savoir.

Je crée quelques UIElements de code derrière et prévoyais la collecte des ordures pour éclaircir des choses. Cependant, les objets ne sont pas sans ed au moment où je m'y attendais. Je les attendais à freeed à RemoveAt (0), mais ils ne sont libérés à la fin du programme.

Comment puis-je faire les objets soient libérés lorsqu'ils sont retirés de la collection Les enfants du Canevas?

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

Le code se cache derrière:

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

Pas de solution correcte

Autres conseils

Modifier

public class MyControl : UserControl

à

public class MyControl : ContentControl

et il va dire au revoir (après la deuxième fois que vous retirez le contrôle.) J'ai également vérifié la mémoire ne fuit pas à l'aide

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

En outre, voir cette :

  

Vous supprimez le TestControl en effaçant grid.Children, mais il est pas immédiatement admissible à la collecte des ordures. Plusieurs opérations asynchrones sur elle sont en attente, et il ne peut pas être GC'd jusqu'à ce que ces opérations complètes (ceux-ci comprennent l'événement est Déchargé et un code de nettoyage dans le moteur de rendu).

     

Je vérifiais que si vous attendez jusqu'à ce que ces opérations complètes (par exemple en programmant une opération Dispatcher à priorité ContextIdle), le TestControl devient admissible à GC, indépendamment de la présence d'une fixation sur le TextBlock.

UserControl doit soit avoir un événement interne qui ne nettoie pas rapidement, ou il pourrait être un bug avec VS2010 RC. Je signaler cette connexion à travers, mais pour basculer maintenant ContentControl.

Puisque vous utilisez UserControl, je suppose que vous devrez également passer à l'aide du modèle generic.xaml. Ce n'est pas trop difficile d'un changement de (et pour la plupart des choses est une meilleure solution.)

Objets C # ne sont pas automatiquement « libéré » dès qu'ils ne sont plus utilisés.

Au contraire, lorsque vous supprimez l'objet de votre contrôle, il devient admissible à la collecte des ordures à ce moment-là, supposant que vous avez pas d'autres références à ce UIElement.

Une fois qu'un objet est « sans racines » (il n'y a pas de références, directement ou indirectement, de tout objet utilisé dans votre application), il devient admissible à la collecte. Le garbage collector sera alors, par la suite, nettoyer votre objet, mais lorsque cela se produit n'est pas quelque chose que vous (en général) le contrôle.

Juste confiance qu'il finira par obtenir nettoyé. C'est la beauté de C # (et .NET en général) -. La gestion et l'inquiétude, cela est géré pour vous


Edit: Après quelques tests, il apparaît que la fenêtre contient une référence à la UIElement jusqu'au prochain passage de mise en page. Vous pouvez forcer cela se produise en ajoutant un appel à:

this.UpdateLayout();

Après avoir retiré l'élément (s) de la toile enfants. Cela entraînera les objets disponibles pour GC.

Il y a 3 générations de la collecte des ordures en C #, même s'il n'y a pas de références à vos objets, il pourrait prendre 3 collections d'ordures pour les libérer.

Vous pouvez utiliser le paramètre de GC.Collect () pour forcer une collecte des ordures de 3e génération,
cependant, la meilleure approuch est de ne pas appeler GC.Collect () vous-même,
au lieu d'utiliser l'interface IDisposable et lier les enfants à un ObservableCollection et quand vous obtenez un événement CollectionChanged Dispose () de tous les objets supprimés.

Vous pouvez trouver cela d'intérêt. J'ai découvert récemment que x: Nom magasins d'extension de balisage une référence au UIElement dans le contrôle parent dans un dictionnaire par calée le nom de chaîne.

Lorsque vous supprimez le UIElement de son parent, le dictionnaire conserve une référence au contrôle.

  

Il y a un débogage de blog / vidéo fuite de mémoire ici: WPF   x: Nom de fuite de mémoire

La solution est de ne pas utiliser x: Nom ou pour assurer que les contrôles qui sont maintenus en vie par x:. Nom sont effacés à ne pas consommer trop de mémoire avant une section de l'arbre visuel est recueilli

Mise à jour: Vous Radier une classe nommée en utilisant la balise 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! 

Nous avons eu le même problème et aussi pensé que cela pourrait être la raison. Mais nous avons analysé notre projet en utilisant des outils profileurs de mémoire et constaté qu'il n'y a rien à voir avec le Grid.Remove ou Grid.RemoveAt. Donc, je pense que ma suggestion est juste un regard a votre projet à l'outil profileur de mémoire et de voir ce qui se passe dans votre projet. espère que cela aide.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top