Freigeben über


Objektverfolgung in der Profilerstellungs-API

Die Garbage Collection fordert den von inaktiven Objekten belegten Speicher zurück und kann den dadurch frei gewordenen Speicherplatz komprimieren. Dadurch werden aktive Objekte innerhalb des Heaps verschoben. In diesem Thema wird erläutert, wie sich das Verschieben von Objekten auf ObjectID-Werte auswirkt und wie die Profilerstellungs-API diese Werte während der Garbage Collection mit und ohne Komprimierung verfolgt werden.

Objektverschiebung

Wenn Objekte verschoben werden, ändern sich die ObjectID-Werte, die durch vorherige Benachrichtigungen zugewiesen wurden. Der interne Zustand des Objekts selbst ändert sich nicht, mit Ausnahme seiner Verweise auf andere Objekte. Nur der Speicherort des Objekts (und damit seine ObjectID) ändert sich. Durch die ICorProfilerCallback::MovedReferences-Benachrichtigung wird bewirkt, dass ein Profiler seine internen Tabellen aktualisiert, in denen Informationen nach der ObjectID verfolgt werden. Der Name der MovedReferences-Methode ist etwas irreführend, da sie auch für Objekte ausgegeben wird, die nicht verschoben wurden.

Die Anzahl der Objekte im Heap kann Tausende oder Millionen umfassen. Es ist praktisch nicht machbar, die Verschiebung solch großer Mengen von Objekten durch Bereitstellung einer Ausgangs- und einer Ziel-ID für jedes Objekt zu verfolgen. Der Garbage Collector verschiebt daher nach Möglichkeit aktive Objekte in Blöcken, sodass diese dann am neuen Speicherort im Heap weiterhin einen zusammenhängenden Block bilden. Die MovedReferences-Benachrichtigung meldet die Ausgangs- und die Ziel-ObjectID dieser zusammenhängenden Blöcke von Objekten.

Angenommen, ein vorhandener ObjectID-Wert (oldObjectID) liegt innerhalb des folgenden Bereichs:

oldObjectIDRangeStart[i] <= oldObjectID < oldObjectIDRangeStart[i] + cObjectIDRangeLength[i]

In diesem Fall ist der Offset vom Anfang des Bereichs bis zum Anfang des Objekts wie folgt:

oldObjectID - oldObjectRangeStart[i]

Für irgendeinen Wert i, der im folgenden Bereich ist:

0 <= i < cMovedObjectIDRanges

Sie können die neue ObjectID wie folgt berechnen:

newObjectID = newObjectIDRangeStart[i] + (oldObjectID – oldObjectIDRangeStart[i])

All diese Rückrufe werden vorgenommen, während die Common Language Runtime (CLR) unterbrochen wird. Deshalb kann sich keiner der ObjectID-Werte ändern, bis die Laufzeit fortgesetzt wird und eine weitere Garbage Collection durchgeführt wird.

Die folgende Abbildung zeigt 10 Objekte vor der Garbage Collection. Ihre Startadressen sind (äquivalent zu ObjectIDs) 08, 09, 10, 12, 13, 15, 16, 17, 18 und 19. Die Objekte mit ObjectIDs 09, 13 und 19 sind tot, und der belegte Speicher wird während Garbage Collection freigegeben.

Objektverschiebung bei der Garbage Collection

Objektverschiebung bei Garbage Collection

Im unteren Teil der Abbildung werden die Objekte nach der Garbage Collection dargestellt. Der Speicherplatz, der durch die inaktiven Objekte eingenommen wurde, wurde für das Speichern von aktiven Objekten zurückgefordert. Die aktiven Objekte im Heap wurden an die neuen Speicherorte verschoben, wie dargestellt. Dadurch ändern sich die ObjectIDs dieser Objekte. In der folgenden Tabelle werden die ObjectIDs vor und nach der Garbage Collection aufgeführt.

Objekt

oldObjectIDRangeStart[]

newObjectIDRangeStart []

0

08

07

1

09

2

10

08

3

12

10

4

13

5

15

11

6

16

12

7

17

13

8

18

14

9

19

In der folgenden Tabelle werden die Informationen durch Angabe der Startpositionen und Größen zusammenhängender Blöcke komprimiert. Diese Tabelle stellt exakt dar, wie die MovedReferences-Methode die Informationen meldet.

Blöcke

oldObjectIDRangeStart[]

newObjectIDRangeStart []

cObjectIDRangeLength []

0

08

07

1

1

10

08

2

2

15

11

4

Erkennen aller gelöschten Objekte

Die MovedReferences-Methode meldet alle Objekte, die nach einer Garbage Collection mit Komprimierung weiter bestehen, unabhängig davon, ob sie verschoben wurden. Objekte, die von MovedReferences nicht gemeldet werden, wurden bei der Garbage Collection gelöscht. Eine Komprimierung findet allerdings nicht bei jeder Garbage Collection statt. Bei .NET Framework, Version 1.0 und 1.1, konnte der Profiler Objekte nicht erkennen, die nach einer Garbage Collection ohne Komprimierung weiterhin vorhanden waren (also einer Garbage Collection, bei der überhaupt keine Objekte verschoben wurden). .NET Framework, Version 2.0, bietet eine bessere Unterstützung dieses Szenarios durch die folgenden neuen Methoden:

Beachten Sie, dass sich eine Garbage Collection komprimierend für eine Generierung und nicht komprimierend für eine andere Generierung auswirken kann. Das bedeutet, dass eine Garbage Collection für eine bestimmte Generierung entweder einen SurvivingReferences-Rückruf oder einen MovedReferences-Rückruf erhält, jedoch nicht beide.

Hinweise

Nach einer Garbage Collection wird eine Anwendung angehalten, bis die Laufzeit die Weitergabe von Informationen über den Heap an den Codeprofiler beendet hat. Sie können die ICorProfilerInfo::GetClassFromObject-Methode verwenden, um die ClassID der Klasse des Objekts zu erhalten. Sie können die ICorProfilerInfo::GetClassIDInfo-Methode oder die ICorProfilerInfo2::GetClassIDInfo2-Methode verwenden, um Metadateninformationen über die Klasse abzurufen.

In .NET Framework, Version 1.0 und 1.1, wird nach Abschluss eines Garbage Collection-Vorgangs erwartet, dass jedes weiter bestehende Objekt ein Stammverweis ist, ein übergeordnetes Objekt hat, das ein Stammverweis ist, oder in einer Generierung vorhanden ist, die nicht erfasst wurde. Manchmal besteht die Möglichkeit, dass Objekte vorhanden sind, die zu keiner dieser Kategorien gehören. Diese Objekte werden entweder von der Laufzeit intern zugeordnet oder sind schwache Verweise auf Delegaten. In .NET Framework, Version 1.0 und 1.1, ermöglicht die Profilerstellungs-API dem Benutzer nicht, diese Objekte zu erkennen.

In .NET Framework, Version 2.0, wurden drei Methoden hinzugefügt, die den Profiler dabei unterstützen, klar zu erkennen, welche Generierungen wann erfasst wurden, und die Objekte zu identifizieren, die Stammelemente sind. Diese Methoden helfen dem Profiler, zu bestimmen, warum Objekte nach einer Speicherbereinigung weiterhin vorhanden sind:

Die ICorProfilerCallback2::RootReferences2-Methode ermöglicht dem Profiler, Objekte zu identifizieren, die durch besondere Handles gehalten werden. Die Generierung verbindet Informationen, die durch die ICorProfilerInfo2::GetGenerationBounds-Methode geliefert werden, in Kombination mit den erfassten Generierungsinformationen, die durch die ICorProfilerCallback2::GarbageCollectionStarted-Methode geliefert werden, um Objekte zu identifizieren, die in nicht erfassten Generierungen vorhanden sind.

Referenz

ICorProfilerCallback::MovedReferences-Methode

ICorProfilerCallback2::SurvivingReferences-Methode

ICorProfilerInfo2::GetGenerationBounds-Methode

Siehe auch

Konzepte

Übersicht über die Profilerstellung