Partager via


Format de fichier instantané du tas

L’examen de l’utilisation de la mémoire dans les applications web peut être difficile. L’outil Mémoire DevTools vous permet d’explorer tous les objets alloués en mémoire par votre application web en prenant un tas instantané. Ces informations sont utiles pour les enquêtes sur les performances, car vous pouvez déterminer quels objets consomment le plus de mémoire.

Toutefois, vous devrez parfois vous concentrer sur des parties spécifiques des données mémoire que l’outil Mémoire n’affiche pas. Dans ce cas, utilisez DevTools pour exporter l’ensemble des données mémoire sous forme de .heapsnapshot fichier JSON.

Cet article décrit la structure et le contenu des .heapsnapshot fichiers JSON afin que vous puissiez créer vos propres outils de visualisation et d’analyse.

Enregistrer un tas instantané

Pour exporter un .heapsnapshot fichier, vous devez d’abord enregistrer un tas instantané dans l’outil Mémoire, comme suit :

  1. Dans Microsoft Edge, accédez au site web à partir duquel vous souhaitez exporter les données.

  2. Appuyez sur Ctrl+Maj+I (Windows, Linux) ou Cmd+Option+I (macOS) pour ouvrir Devtools.

  3. Ouvrez l’outil Mémoire .

  4. Sélectionnez Heap instantané, puis cliquez sur Prendre instantané.

Pour plus d’informations, consultez Enregistrer des instantanés de segment de mémoire à l’aide de l’outil mémoire (« Type de profilage de tas instantané ») .

Exporter et afficher un .heapsnapshot fichier

Une fois que vous avez enregistré un tas instantané, vous pouvez l’exporter.

  1. Dans la barre latérale gauche de l’outil Mémoire, cliquez sur Enregistrer en regard du tas instantané élément que vous venez d’enregistrer.

  2. Remplacez l’extension de fichier par .heapsnapshot.json, pour faciliter l’ouverture du fichier dans un éditeur de texte.

  3. Ouvrez le fichier enregistré dans un éditeur de texte, par exemple Visual Studio Code.

  4. Pour faciliter la lecture du json, dans Visual Studio Code, cliquez avec le bouton droit n’importe où dans le code, puis sélectionnez Mettre en forme le document.

En règle générale, le fichier obtenu .heapsnapshot est différent chaque fois que vous enregistrez et exportez un tas instantané. Les instantanés de tas sont générés dynamiquement, en fonction du contenu de l’application web actuellement inspectée dans DevTools.

Vue d’ensemble du format de .heapsnapshot fichier

La mémoire utilisée par une application web est organisée sous forme de graphe par V8, qui est le moteur JavaScript utilisé par Microsoft Edge. Un graphe est un type de données composé de nœuds (points sur le graphe) et d’arêtes (liens entre les points).

Les données contenues dans le .heapsnapshot fichier représentent la mémoire de l’application web qui graphique efficacement et facilitent le transfert de groupes de données entre le processus du navigateur et DevTools. Le .heapsnapshot fichier contient une représentation aplatissement des relations entre les nœuds et les arêtes, sous la forme d’un objet JSON qui contient des tableaux de nombres et de chaînes. Le fichier a une .heapsnapshot extension de nom de fichier et contient des données au format JSON.

Les données ont deux parties main :

  • Les métadonnées, qui contiennent toutes les informations dont vous avez besoin pour analyser les tableaux de données qui représentent le graphique mémoire.
  • Les données des tableaux, qui contiennent les données réelles nécessaires à la recréation du graphe.

Mise à jour de cette documentation de format de données

Le format du .heapsnapshot fichier, comme indiqué ci-dessous, peut changer à mesure que V8 et DevTools évoluent. Si vous constatez une différence dans la documentation, envoyez vos commentaires dans le référentiel MicrosoftDocs/edge-developer.

Schéma des .heapsnapshot données

Structure de niveau supérieur

Les .heapsnapshot données JSON contiennent un objet racine qui a les propriétés suivantes :

{
    "snapshot": {},
    "nodes": [],
    "edges": [],
    "trace_function_infos": [],
    "trace_tree": [],
    "samples": [],
    "locations": [],
    "strings": []
}
Propriété Description Format
snapshot Contient toutes les informations sur le format des données du graphique en mémoire et leur taille. Object
nodes Toutes les informations nécessaires pour recréer les nœuds du graphe. Pour analyser ces données, utilisez snapshot.meta.node_types et snapshot.meta.node_fields. Array
edges Toutes les informations nécessaires pour recréer les arêtes du graphe. Pour analyser ces données, utilisez snapshot.meta.edge_types et snapshot.meta.edge_fields. Array
trace_function_infos Pas encore documenté Array
trace_tree Pas encore documenté Array
samples Pas encore documenté Array
locations Contient des informations sur l’emplacement du script des nœuds. Pour analyser ces données, utilisez snapshot.meta.location_fields avec le nodes tableau . Array
strings Tableau de toutes les chaînes conservées en mémoire. Il peut s’agir de chaînes, telles que des chaînes définies par l’utilisateur ou du code. Array

Instantané

{
    "snapshot": {     
        "meta": {},
        "node_count": 123,
        "edge_count": 456,
        "trace_function_count": 0
    }
    ...
}
Propriété Description Format
meta Propriétés qui contiennent des informations sur la forme et la taille de chaque objet contenu dans les données du graphique en mémoire. Object
node_count Nombre total de nœuds dans le graphique mémoire. Number
edge_count Nombre total d’arêtes dans le graphique mémoire. Number
trace_function_count Nombre total de fonctions de trace dans le graphique mémoire. Number

Métadonnées d’instantané

{
    "snapshot": {
        "meta": {
            "node_fields": [],
            "node_types": [],
            "edge_fields": [],
            "edge_types": []
        }
    }
    ...
}
Propriété Description Format
node_fields Liste de toutes les propriétés requises pour recréer un nœud. Array
node_types Types de toutes les propriétés requises pour recréer un nœud. Le nombre de types est identique au nombre de propriétés définies dans node_fields. Array
edge_fields Liste de toutes les propriétés requises pour recréer une arête. Array
edge_types Types de toutes les propriétés requises pour recréer une arête. Le nombre de types est identique au nombre de propriétés dans edge_fields. Array

Voici un exemple d’objet de métadonnées :

{
    "snapshot": {
        "meta": {
            "node_fields": [
                "type",
                "name",
                "id",
                "self_size",
                "edge_count",
                "trace_node_id",
                "detachedness"
            ],
            "node_types": [
                [
                    "hidden",
                    "array",
                    "string",
                    "object",
                    "code",
                    "closure",
                    "regexp",
                    "number",
                    "native",
                    "synthetic",
                    "concatenated string",
                    "sliced string",
                    "symbol",
                    "bigint",
                    "object shape"
                ],
                "string",
                "number",
                "number",
                "number",
                "number",
                "number"
            ],
            "edge_fields": [
                "type",
                "name_or_index",
                "to_node"
            ],
            "edge_types": [
                [
                    "context",
                    "element",
                    "property",
                    "internal",
                    "hidden",
                    "shortcut",
                    "weak"
                ],
                "string_or_number",
                "node"
            ]
        }
    }
}

Nodes

Le nodes tableau, qui se trouve au niveau supérieur des .heapsnapshot données, contient toutes les informations nécessaires pour recréer les nœuds du graphe de mémoire.

Pour analyser ce tableau, les informations suivantes sont nécessaires :

  • snapshot.node_count, pour connaître le nombre de nœuds.
  • snapshot.meta.node_fields, pour connaître le nombre de champs de chaque nœud.

Chaque nœud du tableau est représenté par une série de snapshot.meta.node_fields.length nombres. Par conséquent, le nombre total d’éléments dans le nodes tableau est snapshot.node_count multiplié par snapshot.meta.node_fields.length.

Pour recréer un nœud, lisez les nombres du nodes tableau par groupes de taille snapshot.meta.node_fields.length.

L’extrait de code suivant montre les node_fields métadonnées et les données des deux premiers nœuds du graphe :

{
    "snapshot": {
        "meta": {
            "node_fields": [
                "type",
                "name",
                "id",
                "self_size",
                "edge_count",
                "trace_node_id",
                "detachedness"
            ]
            ...
        }
        ...
    },
    "nodes": [
        9,1,1,0,10,0,0,
        2,1,79,12,1,0,0,
        ...
    ]
    ...
}
Index dans le groupe de nœuds Nom Description
0 type Type de nœud. Consultez Types de nœuds ci-dessous.
1 name Nom du nœud. Il s’agit d’un nombre qui est l’index dans le tableau de niveau strings supérieur. Pour trouver le nom réel, utilisez le numéro d’index pour rechercher la chaîne dans le tableau de niveau strings supérieur.
2 id ID unique du nœud.
3 self_size Taille du nœud en octets.
4 edge_count Nombre d’arêtes connectées à ce nœud.
5 trace_node_id ID du nœud de trace
6 detachedness Indique si ce nœud est accessible à partir de l’objet window global. 0 signifie que le nœud n’est pas détaché ; le nœud est accessible à partir de l’objet window global. 1 signifie que le nœud est détaché ; Le nœud n’est pas accessible à partir de l’objet window global.

Types de nœuds

Le premier nombre du groupe de nombres d’un nœud du nodes tableau correspond à son type. Ce nombre est un index qui peut être utilisé pour rechercher le nom du type dans le snapshot.meta.node_types[0] tableau.

Type de nœud Description
Masqué Élément interne V8 qui ne correspond pas directement à un objet JavaScript contrôlable par l’utilisateur. Dans DevTools, tous ces éléments s’affichent sous le nom de catégorie (système). Même si ces objets sont internes, ils peuvent être une partie importante des chemins de rétention.
Objet Tout objet défini par l’utilisateur, tel que { x: 2 } ou new Foo(4). Les contextes, qui apparaissent dans DevTools en tant que système/contexte, contiennent des variables qui devaient être allouées sur le tas, car elles sont utilisées par une fonction imbriquée.
Natif Éléments alloués par le moteur de rendu Blink, plutôt que par V8. Il s’agit principalement d’éléments DOM tels que HTMLDivElement ou CSSStyleRule.
Chaîne concaténée Résultat de la concaténation de deux chaînes avec l’opérateur + . Au lieu de créer une nouvelle chaîne contenant une copie de toutes les données des deux chaînes sources, V8 crée un ConsString objet qui contient des pointeurs vers les deux chaînes sources. Du point de vue de JavaScript, il agit comme n’importe quelle autre chaîne, mais du point de vue du profilage de la mémoire, il est différent.
Chaîne segmentée Résultat d’une opération de sous-chaîne, telle que l’utilisation String.prototype.substr de ou String.prototype.substring. V8 évite de copier des données de chaîne en créant à la place un SlicedString, qui pointe vers la chaîne d’origine et spécifie l’index de début et la longueur. Du point de vue JavaScript, une chaîne segmentée agit comme n’importe quelle autre chaîne, mais du point de vue du profilage de la mémoire, elle est différente.
Tableau Différentes listes internes, qui sont affichées dans DevTools avec le nom de catégorie (tableau). Comme Hidden, cette catégorie regroupe une variété d’éléments. La plupart des objets ici sont nommés (propriétés de l’objet) ou (éléments d’objet), ce qui indique qu’ils contiennent les propriétés à clé de chaîne ou à clé numérique d’un objet JavaScript.
Code Éléments qui augmentent proportionnellement à la quantité de script et/ou au nombre d’exécutions des fonctions.
Synthétique Les nœuds synthétiques ne correspondent pas à quoi que ce soit réellement alloué en mémoire. Ils sont utilisés pour distinguer les différents types de racines de garbage collection (GC).

Bords

À l’instar du nodes tableau, le edges tableau de niveau supérieur contient tous les éléments nécessaires pour recréer les bords du graphe de mémoire.

De même que pour les nœuds, le nombre total d’arêtes peut être calculé en multipliant snapshot.edge_count par snapshot.meta.edge_fields.length. Les arêtes sont également stockées sous la forme d’une séquence de nombres, sur lesquelles vous devrez itérer par groupes de taille snapshot.meta.edge_fields.length.

Toutefois, pour lire correctement le edges tableau, vous devez d’abord lire le nodes tableau, car chaque nœud sait combien d’arêtes il possède.

Pour recréer une arête, vous avez besoin de trois informations :

  • Type d’arête.
  • Nom ou index de l’arête.
  • Nœud auquel le bord est connecté.

Par exemple, si vous lisez le premier nœud du nodes tableau et que sa edge_count propriété est définie sur 4, les quatre premiers groupes de snapshot.meta.edge_fields.length nombres du edges tableau correspondent aux quatre bords de ce nœud.

Index dans le groupe edge Nom Description
0 type Type de bord. Consultez Types Edge pour savoir quels sont les types possibles.
1 name_or_index Il peut s’agir d’un nombre ou d’une chaîne. S’il s’agit d’un nombre, il correspond à l’index dans le tableau de niveau strings supérieur, où se trouve le nom de l’arête.
2 to_node Index dans le nodes tableau auquel cette arête est connectée.

Types d’arêtes

Le premier nombre du groupe de nombres d’une arête dans le edges tableau correspond à son type. Ce nombre est un index qui peut être utilisé pour rechercher le nom du type dans le snapshot.meta.edge_types[0] tableau.

Type d’arête Description
Interne Les arêtes qui ne correspondent pas aux noms visibles par JavaScript, mais qui restent importantes. Par exemple, les instances de fonction ont un « contexte » représentant l’état des variables qui se trouvaient dans l’étendue où la fonction a été définie. Il n’existe aucun moyen pour le code JavaScript de lire directement le « contexte » d’une fonction, mais ces arêtes sont nécessaires lors de l’examen des rétentions.
Faible Les bords faibles ne conservent pas le nœud auquel ils sont connectés et sont donc omis de la vue Des rétentions. Tout objet avec des bords faibles pointant vers celui-ci peut être ignoré par le garbage collection (GC).
Masqué Comme interne, à l’exception de ces arêtes n’ont pas de noms uniques et sont numérotées dans l’ordre croissant.
Raccourci Représentation plus facile à lire d’un autre chemin d’accès. Ce type est rarement utilisé. Par exemple, si vous utilisez Function.prototype.bind pour créer une fonction liée avec des arguments liés, V8 crée un JSBoundFunction, qui pointe vers un FixedArray (un type interne), qui pointe vers chaque argument lié. Lors de la production d’un instantané, V8 ajoute un bord de raccourci de la fonction liée directement à chaque argument lié, en contournant .FixedArray
Élément Propriétés de l’objet où la clé est un nombre.

emplacements

Le locations tableau, qui se trouve au niveau supérieur des .heapsnapshot données, contient des informations sur l’emplacement où certains nœuds du instantané ont été créés. Ce tableau se compose d’une série de nombres destinés à être lus par groupes de taille snapshot.meta.location_fields.length. Par conséquent, nous allons accéder à snapshot.meta.location_fields pour connaître le nombre de champs de chaque emplacement dans le locations tableau et ce que sont ces champs. Par exemple, si location_fields contient 4 éléments, le locations tableau doit être lu par groupes de 4.

snapshot.meta.location_fields contient les informations pour chaque emplacement :

Indexer dans location_fields Nom Description
0 object_index Index du nœud dans le snapshot.nodes tableau associé à cet emplacement.
1 script_id ID du script qui crée le nœud associé.
2 line Numéro de ligne où le nœud a été créé, dans le script qui a créé le nœud.
3 column Numéro de colonne dans lequel le nœud a été créé, dans le script qui a créé le nœud.

L’exemple de code suivant montre comment lier le snapshot.locations tableau au snapshot.nodes tableau :

{
    "snapshot": {
        "meta": {
            "location_fields": [
                "object_index",
                "script_id",
                "line",
                "column"
            ]
            ...
        }
        ...
    },
    "nodes": [
        9,1,1,0,10,0,0,
        2,1,79,12,1,0,0,
        ...
    ],
    "locations":[
        7,9,0,0,
        113792,3,25,21,
        ...
    ],
    ...
}

Le premier emplacement du locations tableau est 7,9,0,0,. Cet emplacement est associé au groupe d’informations de nœud qui commence à l’index 7 dans le nodes tableau. Par conséquent, le nœud contient les paires clé/valeur suivantes :

"type": 2,
"name": 1,
"id": 79,
"self_size": 12,
"edge_count": 1,
"trace_node_id": 0,
"detachedness": 0,
"script_id": 9,
"line" 0,
"column": 0,

Voir aussi

Pour en savoir plus sur le format de .heapsnapshot fichier, consultez le code qui génère le fichier, qui est la HeapSnapshotGenerator classe dans heap-snapshot-generator.h.