Ich habe versucht, den einfachsten Code zu finden, um zu reproduzieren, was ich sehe. Das vollständige Programm ist unten, aber ich werde es hier beschreiben. Angenommen, ich habe die Klasse ListData
, die nur einige Eigenschaften hat. Dann nehme ich an, dass ich eine Klasse MyList
mit einem Mitglied List<ListData> m_list
habe. Angenommen, m_list
wird im Konstruktor MyList
initialisiert.
In der Hauptmethode erzeuge ich einfach eines dieser MyList
-Objekte, füge ein paar ListData
hinzu und lasse es dann außerhalb des Bereichs liegen. Ich mache einen Schnappschuss in dotMemory, nachdem die ListData
hinzugefügt wurden, dann nehme ich einen weiteren Schnappschuss, nachdem das Objekt MyList
den Gültigkeitsbereich verlassen hat.
In dotMemory kann ich sehen, dass das Objekt MyList
wie erwartet zurückgefordert wurde. Ich sehe auch, dass die zwei ListData
-Objekte, die ich erstellt habe, auch wie erwartet zurückgefordert wurden.
Was ich nicht verstehe, warum gibt es ein ListData[]
, das überlebt hat?
Hier ist ein Screenshot von diesem:
Ich öffne überlebte Objekte auf dem neuesten Snapshot für die ListData[]
, dann sehe ich Key Retention Paths, das ist was ich sehe.
Ich bin neu in der .NET-Speicherverwaltung und habe diese Beispiel-App erstellt, die mir hilft, sie zu erkunden. Ich habe die Testversion von JetBrains dotMemory Version 4.3 heruntergeladen. Ich verwende Visual Studio 2013 Professional. Ich muss Speicherverwaltung lernen, damit ich die Speicherprobleme beheben kann, die wir bei der Arbeit haben.
Hier ist das vollständige Programm, das verwendet werden kann, um dies zu reproduzieren. Es ist nur eine schnelle und dreckige App, aber es wird das bekommen, wonach ich frage, wenn Sie es profilieren.
%Vor%Schritte:
Beachten Sie, dass die MyList-Objekte und die zwei ListData-Objekte eine Speicherbereinigung erhielten, die ListData [] jedoch nicht. Warum hängt ein ListData [] herum? Wie kann ich dafür sorgen, dass Müll gesammelt wird?
Warum hängt ein ListData [] herum? Wie kann ich es schaffen? Müll gesammelt?
Wenn Sie den "Creation Stack Trace" in dotMemory betrachten, sehen Sie:
Dies zeigt Ihnen, dass die leere ListData[0]
Instanz über den statischen Konstruktor von List<T>
erstellt wurde. Wenn Sie sich die Quelle ansehen , sehen Sie Folgendes:
List<T>
initialisiert ein leeres Standard-Array, um die Vermeidung einer solchen Zuweisung jedes Mal zu optimieren, wenn Sie ein neues List<T>
erstellen. Dies ist der Standardkonstruktor:
Wenn Sie nur List<T>.Add
verwenden, ändert sich die Größe des Arrays.
static
-Member werden aus "High Frequency Heap" referenziert, die einmal für erstellt wurden jedes AppDomain
in Ihrer Anwendung. Das gepinnte object[]
, das Sie sehen, ist der Ort, an dem alle static
Instanzen gespeichert sind.
Da die Instanz static
ist, bleibt sie für die gesamte Lebensdauer Ihrer Anwendung im Speicher.
Tags und Links .net c# memory-management