Dans WPF: Children.Remove ou Children.Clear ne libère pas d'objets
Mise à jour: j'ai essayé sur un autre, plus proprement installé, la machine. Je ne pouvais pas reproduire ce sur cette machine. Si je trouve ce que la récidive (VSStudio) composant est à l'origine de cela, je vais vous laisser savoir.
Je créer un certain UIElements de code derrière et a anticiper la collecte des ordures pour effacer les trucs. Cependant, les objets ne sont pas libres-ed au moment où je m'y attendais. Je m'attendais à être freeed à RemoveAt(0), mais ils ne sont libérés à la fin du programme.
Comment rendre les objets d'être libéré lorsqu'il est retiré de la collection d'Enfants de la Toile?
<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 derrière est:
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");
}
}
source d'informationauteur Bart Roozendaal
Vous devez vous connecter pour publier un commentaire.
Changement
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 aussi vérifié la mémoire n'a pas de fuite en utilisant
Debug.WriteLine("mem: " + GC.GetTotalMemory(true).ToString());
Aussi, voir cette:
UserControl doit avoir soit un événement interne qui n'a pas de nettoyer rapidement, ou peut-être un bug avec VS2010 RC. Je voudrais signaler ce par le biais de se connecter, mais pour passer maintenant à ContentControl.
Depuis que vous utilisez UserControl, je suppose que vous avez aussi de passer à l'utilisation des Génériques.xaml modèle. Ce n'est pas trop difficile de, un changement de contrôle (et pour la plupart des choses est une meilleure solution.)
Objets en C# ne sont pas automatiquement "libéré" dès qu'ils ne sont plus utilisés.
Plutôt, lorsque vous retirez l'objet de votre Contrôle, il devient admissibles pour la collecte des ordures à ce stade, en supposant que vous n'avez pas d'autres références à la UIelement.
Une fois qu'un objet est "non" (il n'y a pas de références, directement ou indirectement, de tout objet utilisé dans votre application), il devient admissible à la collection. Le garbage collector puis, finalement, le nettoyage de votre objet, mais lorsque cela arrive, n'est pas quelque chose que vous (généralement) de contrôle.
Seulement de la confiance qu'il finira par être nettoyé. C'est la beauté de C# (et .NET en général) - la gestion, et de s'inquiéter de ce qui est fait pour vous.
Edit: Après quelques tests, il semble que la Fenêtre contient une référence à l'UIelement jusqu'à la prochaine passe de mise en page. Vous pouvez forcer cette à produire par l'ajout d'un appel à:
Après le retrait de l'élément(s) de la zone de travail des Enfants. Cela entraînera les objets disponibles pour GC.
Il y a 3 générations de collecte des ordures en C#, donc même si il n'y a pas de références à vos objets, il peut prendre 3 garbage collections gratuit.
Vous pouvez utiliser le GC.Collect()'s paramètre pour forcer une 3e génération de la collecte des ordures,
cependant, le meilleur approuch est de ne pas appeler GC.Collect() vous-même,
au lieu d'utiliser l'interface IDisposable et lient les Enfants à une ObservableCollection
et quand vous obtenez un événement CollectionChanged Dispose() de tous les objets déplacés.
Vous pouvez trouver cela d'intérêt. J'ai découvert récemment que x:Nom de l'extension de balisage stocke une référence à la UIElement dans le contrôle parent dans un dictionnaire identifié par le nom de la chaîne.
Lorsque vous retirez le UIElement de son parent, le dictionnaire conserve une référence à la commande.
La solution est de ne pas utiliser x:Nom ou pour s'assurer que les contrôles qui sont maintenues en vie par x:Name sont éliminés afin de ne pas consommer trop de mémoire avant une section de l'arbre visuel est recueillie.
Mise à jour: Vous faire radier l'enregistrement d'un nom de classe à l'aide de la Portée de nom
Nous avons eu le même problème et pense que cela peut être la raison. Mais nous avons analysé notre projet à l'aide de la Mémoire profiler outils et constaté qu'il n'y a rien à faire avec la Grille.De supprimer ou de Grille.RemoveAt. Je pense donc que ma suggestion est juste un coup d'oeil de votre projet à la mémoire de l'outil générateur de profils et de voir ce qui se passe à l'intérieur de votre projet. espère que cette aide.