Situation
Nach diesem akzeptierte Antwort , wenn die " GC 'sieht' eine zyklische Referenz von 2 oder mehr Objekten, die nicht von anderen Objekten oder permanenten GC-Handles referenziert werden, werden diese Objekte gesammelt."
Ich wollte wissen, ob Garbage Collection für eine super einfache Baumstruktur funktioniert, die nicht einmal Inhalt hat, nur Baumknoten mit Eltern- und Kind-Referenzen.
Stellen Sie sich vor, Sie erstellen einen Wurzelknoten, fügen diesem ein Kind hinzu und dann ein Kind dem Kind und so weiter, also nicht wirklich ein Baum, sondern eher eine Liste (jeder Knoten hat höchstens ein Kind und ein Elternteil).
Wenn wir dann das Kind der Wurzel und alle Verweise auf Knoten innerhalb des Teilbaums dieses Kindes entfernen, wie ich die obige Antwort verstehe, sollte der Garbage Collector den Teilbaum bereinigen.
Beschreibung des Problems
Wenn Sie einen Blick auf die Main-Methode im unten stehenden Testcode werfen, wird bei Wenn ich die Exe aus dem Release-Verzeichnis ausführe, erhalte ich das Verhalten, das ich erwarten würde Der Speicherverbrauch steigt auf ~1GB, geht dann auf ~27MB (nach dem 1. GC.collect) wieder hoch und dann wieder auf ~27MB (für das 2. GC.collect).
Wenn nun Ausführung im Debugger Der Speicherverbrauch für diesen Vorgang steigt auf ~1GB und für die 1.GC.collect bleibt der Speicherverbrauch genau dort, wo er war, steigt dann auf 1.6GB innerhalb der 2. for-Schleife und dauert dort ewig und dann bekomme ich endlich eine OutOfMemoryException innerhalb der 2. for-Schleife.
Fragen
Warum tritt dieses Verhalten im Debugger auf?
Sollte die Garbage Collection nicht auch während des Debuggens funktionieren, fehlt mir da eine Info über den Debugger?
Nebenbemerkungen
- Ich verwende Visual Studio 2010 Express Edition
- Ich rufe GC.Collect() nur zu Testzwecken auf, um sicher zu sein, dass die Garbage Collection stattgefunden hat (ich habe nicht vor, sie normalerweise zu verwenden).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Tree
{
class Program
{
static void Main(string[] args)
{
TreeNode root = new TreeNode(null); // the null-argument is the parent-node
TreeNode node = root;
for (int i = 0; i < 15000000; i++)
{
TreeNode child = new TreeNode(node);
node = child;
}
root.RemoveChild(root.Children[0] );
node = root;
GC.Collect();
for (int i = 0; i < 15000000; i++)
{
TreeNode child = new TreeNode(node);
node = child;
}
root.RemoveChild(root.Children[0]);
node = root;
GC.Collect();
Console.ReadLine();
}
}
}
Ich füge den folgenden Code nur für den Fall ein, dass Sie ihn selbst testen möchten, er ist nicht wirklich nützlich
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Tree
{
class TreeNode
{
public TreeNode Parent { get; private set; }
public List<TreeNode> Children { get; set; }
public TreeNode(TreeNode parent)
{
// since we are creating a new node we need to create its List of children
Children = new List<TreeNode>();
Parent = parent;
if(parent != null) // the root node doesn't have a parent-node
parent.AddChild(this);
}
public TreeNode(TreeNode parent, List<TreeNode> children)
{
// since we are creating a new node we need to create its List of children
Children = new List<TreeNode>();
Parent = parent;
if (parent != null) // the root node doesn't have a parent-node
parent.AddChild(this);
Children = children;
}
public void AddChild(TreeNode child)
{
Children.Add(child);
}
public void RemoveChild(TreeNode child)
{
Children.Remove(child);
}
}
}