Partager via


Suivi d'objet dans l'API de profilage

Le garbage collection récupère de la mémoire occupée par des objets morts et peut compacter l'espace libéré. Les objets actifs sont par conséquent déplacés dans le tas. Cette rubrique explique l'influence du déplacement d'objets sur les valeurs ObjectID et le suivi de ces valeurs par l'API de profilage pendant le garbage collection de compactage et de non-compactage.

Déplacement d'objets

Lorsque des objets sont déplacés, les valeurs ObjectID qui ont été assignées par des notifications précédentes changent. L'état interne de l'objet lui-même ne change pas, à l'exception de ses références à d'autres objets. Seul l'emplacement de l'objet dans la mémoire (et par conséquent son ObjectID) change. La notification ICorProfilerCallback::MovedReferences permet à un profileur de mettre à jour ses tables internes qui suivent les informations par ObjectID. Le nom de la méthode MovedReferences est quelque peu trompeur, car elle est aussi émise pour les objets qui n'ont pas été déplacés.

Le nombre d'objets dans le tas peut se compter en milliers ou en millions. Il serait irréaliste de suivre le déplacement d'un si grand nombre d'objets en fournissant un ID avant et après pour chaque objet. Le garbage collector a par conséquent tendance à déplacer des objets actifs contigus en blocs, de telle sorte qu'ils demeurent contigus dans leurs nouveaux emplacements dans le tas. La notification MovedReferences signale les ObjectID avant et après de ces blocs contigus d'objets.

Supposez qu'une valeur ObjectID existante (oldObjectID) se trouve dans la plage suivante :

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

L'offset du début de la plage jusqu'au début de l'objet est, dans ce cas, le suivant :

oldObjectID - oldObjectRangeStart[i]

Pour toute valeur d'i qui se trouve dans la plage suivante :

0 <= i < cMovedObjectIDRanges

vous pouvez calculer le nouvel ObjectID de la manière suivante :

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

Tous ces rappels sont effectués pendant l'interruption du Common Language Runtime (CLR). Aucune des valeurs ObjectID ne peut par conséquent changer tant que le runtime n'a pas repris et qu'un autre garbage collection n'a pas été effectué.

10 objets avant le garbage collection sont illustrés ci-dessous. Leurs adresses de début (équivalentes aux ObjectID) sont 08, 09, 10, 12, 13, 15, 16, 17, 18 et 19. Les objets ayant pour ObjectID 09, 13 et 19 sont morts et leur espace sera récupéré pendant le garbage collection.

Déplacement d'objets pendant le garbage collection

Mouvement des objets pendant le garbage collection

La partie inférieure de l'illustration montre les objets après le garbage collection. L'espace qui était occupé par les objets morts a été récupéré pour y conserver des objets actifs. Les objets actifs qui figurent dans le tas ont été déplacés vers les nouveaux emplacements qui sont indiqués. Leur ObjectID va par conséquent changer. L'ObjectID avant et après le garbage collection est indiqué dans le tableau suivant.

Objet

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

Dans le tableau ci-dessous, les informations sont compactées avec spécification de la position de départ et de la taille des blocs contigus. Ce tableau illustre avec précision comment la méthode MovedReferences signale les informations.

Blocs

oldObjectIDRangeStart[]

newObjectIDRangeStart[]

cObjectIDRangeLength[]

0

08

07

1

1

10

08

2

2

15

11

4

Détection de tous les objets supprimés

La méthode MovedReferences signale tous les objets qui survivent à un garbage collection de compactage, qu'ils soient déplacés ou non. Tout objet non signalé par MovedReferences n'a pas survécu. Tous les garbage collections ne procèdent pas à un compactage. Dans les versions 1.0 et 1.1 du .NET Framework, le profileur ne pouvait pas détecter les objets qui survivaient à un garbage collection de non-compactage (un garbage collection au cours duquel aucun objet n'est déplacé). La version 2.0 du .NET Framework assure une meilleure prise en charge pour ce scénario grâce aux nouvelles méthodes suivantes :

Notez qu'un seul garbage collection peut compacter une génération et ne pas en compacter une autre. En d'autres termes, toute génération donnée recevra des rappels SurvivingReferences ou MovedReferences pour un garbage collection donné, mais pas pour les deux.

Notes

Après un garbage collection, une application reste arrêtée tant que le runtime n'a pas terminé de passer des informations sur le tas au profileur de code. Vous pouvez utiliser la méthode ICorProfilerInfo::GetClassFromObject pour obtenir le ClassID de la classe de l'objet. Vous pouvez utiliser la méthode ICorProfilerInfo::GetClassIDInfo ou ICorProfilerInfo2::GetClassIDInfo2 pour obtenir des informations de métadonnées sur la classe.

Dans les versions 1.0 et 1.1 du .NET Framework, lorsqu'une opération de garbage collection est terminée, chaque objet survivant est supposé être une référence racine, avoir un parent qui est une référence racine ou exister dans une génération qui n'a pas été collectée. Certains objets peuvent parfois n'appartenir à aucune de ces catégories. Ces objets sont soit alloués en interne par le runtime, soit des références faibles à des délégués. Dans les versions 1.0 et 1.1 du .NET Framework, l'API de profilage ne permet pas à l'utilisateur d'identifier ces objets.

Dans la version 2.0 du .NET Framework, trois méthodes ont été ajoutées pour aider le profileur à indiquer clairement les générations qui sont collectées et le moment auquel elles le sont et identifier les objets qui sont des racines. Ces méthodes permettent au profileur de déterminer les raisons pour lesquelles des objets subsistent après une collection :

La méthode ICorProfilerCallback2::RootReferences2 permet au profileur d'identifier les objets qui sont conservés par des handles spéciaux. Les informations sur les limites des générations fournies par la méthode ICorProfilerInfo2::GetGenerationBounds combinées aux informations sur les générations collectées fournies par la méthode ICorProfilerCallback2::GarbageCollectionStarted permettent au profileur d'identifier les objets qui existent dans les générations qui n'ont pas été collectées.

Référence

ICorProfilerCallback::MovedReferences, méthode

ICorProfilerCallback2::SurvivingReferences, méthode

ICorProfilerInfo2::GetGenerationBounds, méthode

Voir aussi

Concepts

Vue d'ensemble du profilage