Enregistrer des instantanés de tas à l’aide de l’outil Mémoire

Utilisez le profileur de tas dans l’outil Mémoire pour effectuer les opérations suivantes :

  • Enregistrez des captures instantanées de tas JavaScript (tas JS).
  • Analyser les graphiques de mémoire.
  • Comparer les instantanés.
  • Rechercher les fuites de mémoire.

Le profileur de tas DevTools affiche la distribution de mémoire utilisée par les objets JavaScript et par les nœuds DOM associés sur la page web rendue.

Prendre un instantané

  1. Ouvrez la page web que vous souhaitez analyser. Par exemple, ouvrez la page de démonstration Objets dispersés dans une nouvelle fenêtre ou un nouvel onglet.

  2. Pour ouvrir DevTools, cliquez avec le bouton droit sur la page web, puis sélectionnez Inspecter. Vous pouvez également appuyer sur Ctrl+Maj+I (Windows, Linux) ou Cmd+Option+I (macOS). DevTools s’ouvre.

  3. Dans DevTools, dans la barre d’activité, sélectionnez l’onglet Mémoire . Si cet onglet n’est pas visible, cliquez sur le bouton Autres outils (icône Autres outils).

  4. Dans la section Sélectionner le type de profilage, sélectionnez le bouton d’option Tas instantané.

  5. Sous Sélectionner une machine virtuelle JavaScript instance, sélectionnez la machine virtuelle JavaScript que vous souhaitez profiler.

  6. Cliquez sur le bouton Prendre instantané :

L’outil Mémoire, l’option Instantané tas est sélectionnée et le bouton Prendre instantané est mis en surbrillance

Une fois que le instantané de segment de mémoire nouvellement enregistré a été chargé dans DevTools et analysé, le instantané s’affiche et une nouvelle entrée s’affiche dans la barre latérale Profils sous INSTANTANÉS DU TAS :

Taille totale des objets accessibles

Le numéro sous le nouvel élément de barre latérale indique la taille totale des objets JavaScript accessibles. Pour en savoir plus sur les tailles d’objet dans le tas instantané, consultez Tailles et distances des objets dans la terminologie mémoire.

Le instantané affiche uniquement les objets du graphique mémoire accessibles à partir de l’objet global. La prise d’une instantané commence toujours par un garbage collection.

Prenez une autre instantané

Pour prendre une autre instantané lorsqu’un est déjà affiché dans l’outil Mémoire, dans la barre latérale, cliquez sur Profils au-dessus du instantané existant :

Le bouton Profils pour prendre une autre instantané

Effacer les instantanés

Pour effacer tous les instantanés de l’outil Mémoire , cliquez sur l’icône Effacer tous les profils (icône effacer) :

Supprimer des instantanés

Afficher les instantanés

Les instantanés de tas peuvent être consultés de plusieurs façons différentes dans l’outil Mémoire . Chaque façon d’afficher un tas instantané dans l’interface utilisateur correspond à une tâche différente :

View Contenu Utilisé pour
Résumé Affiche les objets regroupés par nom de constructeur. Recherche d’objets et de la mémoire qu’ils utilisent, en fonction des types regroupés par nom de constructeur. Utile pour le suivi des fuites DOM.
Comparaison Affiche les différences entre deux instantanés. Comparaison de deux instantanés mémoire (ou plus) avant et après une opération. L’inspection du delta dans la mémoire libérée et l’inspection du nombre de références vous aident à confirmer la présence et la cause d’une fuite de mémoire, et à en déterminer la cause.
Confinement Permet l’exploration du contenu du tas. Fournit une meilleure vue de la structure des objets, ce qui permet d’analyser les objets référencés dans l’espace de noms global (fenêtre) pour déterminer ce qui maintient les objets autour. Utilisez-le pour analyser les fermetures et plonger dans vos objets à un niveau inférieur.

Pour basculer entre les vues, utilisez la liste déroulante en haut de l’outil Mémoire :

Sélecteur de basculement de vues

Remarque

Toutes les propriétés ne sont pas stockées sur le tas JavaScript. Les propriétés implémentées à l’aide de getters qui exécutent du code natif ne sont pas capturées. En outre, les valeurs autres que les chaînes telles que les nombres ne sont pas capturées.

Vue récapitulative

Au départ, un tas instantané s’ouvre dans la vue Résumé, qui affiche une liste de constructeurs :

Vue récapitulative

Chaque constructeur de la liste peut être développé pour afficher les objets qui ont été instanciés à l’aide de ce constructeur.

Pour chaque constructeur de la liste, la vue Résumé affiche également un nombre tel que ×123, indiquant le nombre total d’objets créés avec le constructeur. La vue Résumé affiche également les colonnes suivantes :

Nom de colonne Description
Distance Affiche la distance à la racine à l’aide du chemin d’accès simple le plus court des nœuds. Consultez La terminologie distance dans la mémoire.
Taille superficielle Affiche la somme des tailles superficielles de tous les objets créés par une fonction de constructeur spécifique. La taille superficielle est la taille du tas JavaScript qui est directement détenu par un objet. La taille superficielle d’un objet est généralement petite, car un objet JavaScript stocke souvent uniquement sa description de l’objet, et non les valeurs, dans la mémoire directement détenue de l’objet. La plupart des objets JavaScript stockent leurs valeurs dans un magasin de stockage qui se trouve ailleurs dans le tas JavaScript et exposent uniquement un petit objet wrapper sur la partie du tas JavaScript qui appartient directement à l’objet. Consultez Taille superficielle dans la terminologie de la mémoire.
Taille conservée Affiche la taille maximale conservée parmi le même ensemble d’objets. La taille de la mémoire que vous pouvez libérer après la suppression d’un objet (et que les dépendants ne sont plus accessibles) est appelée taille conservée. Consultez Taille conservée dans la terminologie de la mémoire.

Après avoir développé un constructeur dans la vue Résumé , toutes les instances du constructeur s’affichent. Pour chaque instance, les tailles superficielles et conservées sont affichées dans les colonnes correspondantes. Le nombre après le @ caractère est l’ID unique de l’objet, ce qui vous permet de comparer des instantanés de tas par objet.

Entrées de constructeur dans l’affichage Résumé

L’affichage Résumé de l’outil Mémoire répertorie les groupes de constructeurs d’objets :

Groupes de constructeurs

Les groupes de constructeurs dans l’affichage Résumé peuvent être des fonctions intégrées telles que Array ou Object , ou il peut s’agir de fonctions définies dans votre propre code.

Pour afficher la liste des objets qui ont été instanciés par un constructeur donné, développez le groupe de constructeurs.

Noms de catégorie spéciaux dans l’affichage Résumé

La vue Résumé contient également des noms de catégorie spéciaux qui ne sont pas basés sur des constructeurs. Ces catégories spéciales sont les suivantes :

Nom de catégorie Description
(tableau) Divers objets internes de type tableau qui ne correspondent pas directement aux objets visibles à partir de JavaScript, tels que le contenu des tableaux JavaScript ou les propriétés nommées des objets JavaScript.
(code compilé) Données internes dont V8 (moteur JavaScript de Microsoft Edge) a besoin pour exécuter des fonctions définies par JavaScript ou WebAssembly. V8 gère automatiquement l’utilisation de la mémoire dans cette catégorie : si une fonction s’exécute plusieurs fois, V8 utilise davantage de mémoire pour cette fonction afin que la fonction s’exécute plus rapidement. Si une fonction ne s’est pas exécutée depuis un certain temps, V8 peut supprimer les données internes de cette fonction.
(chaîne concaténée) Lorsque deux chaînes sont concaténées ensemble, comme lors de l’utilisation de l’opérateur JavaScript + , V8 peut choisir de représenter le résultat en interne sous la forme d’une chaîne concaténée. Au lieu de copier tous les caractères des deux chaînes dans une nouvelle chaîne, V8 crée un petit objet qui pointe vers les deux chaînes.
InternalNode Objets alloués en dehors de V8, tels que les objets C++ définis par Blink, le moteur de rendu de Microsoft Edge.
(forme d’objet) Informations sur les objets, telles que le nombre de propriétés qu’ils possèdent et une référence à leurs prototypes, que V8 gère en interne lors de la création et de la mise à jour des objets. Cela permet à V8 de représenter efficacement les objets avec les mêmes propriétés.
(chaîne segmentée) Lors de la création d’une sous-chaîne, par exemple lors de l’utilisation de la méthode JavaScript substring , V8 peut choisir de créer un objet de chaîne segmentée plutôt que de copier tous les caractères pertinents de la chaîne d’origine. Ce nouvel objet contient un pointeur vers la chaîne d’origine et décrit la plage de caractères de la chaîne d’origine à utiliser.
system / Context Variables locales à partir d’une étendue JavaScript accessible par une fonction imbriquée. Chaque fonction instance contient un pointeur interne vers le contexte dans lequel elle s’exécute, afin qu’elle puisse accéder à ces variables.
(système) Divers objets internes qui n’ont pas encore été classés de manière plus significative.

Vue de comparaison

Pour rechercher les objets fuites, comparez plusieurs instantanés les uns aux autres. Dans une application web, en règle générale, l’exécution d’une action, puis l’action inverse ne doit pas conduire à davantage d’objets en mémoire. Par exemple, lors de l’ouverture d’un document, puis de sa fermeture, le nombre d’objets en mémoire doit être le même qu’avant l’ouverture du document.

Pour vérifier que certaines opérations ne créent pas de fuites :

  1. Prenez un tas instantané avant d’effectuer une opération.

  2. Effectuez l’opération. Autrement dit, interagissez avec la page d’une manière ou d’une autre, ce qui peut provoquer une fuite.

  3. Effectuez l’opération inverse. Autrement dit, faites l’interaction inverse et répétez-la plusieurs fois.

  4. Prenez un deuxième tas instantané.

  5. Dans le deuxième segment de mémoire instantané, remplacez l’affichage par Comparaison, en le comparant à l’instantané 1.

Dans la vue Comparaison , la différence entre deux instantanés s’affiche :

Vue de comparaison

Lorsque vous développez un constructeur dans la liste, les instances d’objet ajoutées et supprimées s’affichent.

Affichage contenant-contenu

La vue Contenant-contenu vous permet d’examiner les fermetures de fonctions, d’observer les objets internes de machine virtuelle qui composent vos objets JavaScript et de comprendre la quantité de mémoire utilisée par votre application à un niveau très bas :

Affichage contenant-contenu

La vue Contenant-contenu affiche les types d’objets suivants :

Points d’entrée de la vue d’endiguement Description
Objets DOMWindow Objets globaux pour le code JavaScript.
Racines du GC Racines GC utilisées par le garbage collector de la machine virtuelle JavaScript. Les racines gc sont composées de mappages d’objets intégrés, de tables de symboles, de piles de threads de machine virtuelle, de caches de compilation, d’étendues de handle et de handles globaux.
Objets natifs Objets créés par le navigateur, tels que les nœuds DOM et les règles CSS, qui sont affichés dans la machine virtuelle JavaScript pour autoriser l’automatisation.

La section Retainers

La section Retainers s’affiche en bas de l’outil Mémoire et affiche tous les objets qui pointent vers l’objet sélectionné. La section Retainers est mise à jour lorsque vous sélectionnez un autre objet dans la vue Résumé, Contenant-contenu ou Comparaison .

Dans la capture d’écran suivante, un objet chaîne a été sélectionné dans la vue Résumé, et la section Retainers montre que la chaîne est conservée par la x propriété d’un instance de la Item classe, qui se trouve dans le example-03.js fichier :

La section Retainers

Masquer les cycles

Dans la section Retainers , lorsque vous analysez les objets qui conservent l’objet sélectionné, vous pouvez rencontrer des cycles. Des cycles se produisent lorsque le même objet apparaît plusieurs fois dans le chemin de rétention de l’objet sélectionné. Dans la section Retainers , un objet cycle est indiqué par grisé.

Pour simplifier le chemin de rétention, masquez les cycles dans la section Rétentions en cliquant sur le menu déroulant Filtrer les arêtes , puis en sélectionnant Masquer les cycles :

Le menu déroulant Filtrer les bords dans la section Rétentions, « Masquer les cycles » est sélectionné

Masquer les nœuds internes

Les nœuds internes sont des objets spécifiques à V8 (moteur JavaScript dans Microsoft Edge).

Pour masquer les nœuds internes dans la section Rétentions , dans le menu déroulant Filtrer les arêtes , sélectionnez Masquer l’interne.

Configurer la colonne Taille superficielle pour inclure la taille entière d’un objet

Par défaut, la colonne Taille superficielle de l’outil Mémoire inclut uniquement la taille de l’objet lui-même. La taille superficielle est la taille du tas JavaScript qui est directement détenu par un objet. La taille superficielle d’un objet est généralement petite, car un objet JavaScript stocke souvent uniquement sa description de l’objet, et non les valeurs, dans la mémoire directement détenue de l’objet. La plupart des objets JavaScript stockent leurs valeurs dans un magasin de stockage qui se trouve ailleurs dans le tas JavaScript et exposent uniquement un petit objet wrapper sur la partie du tas JavaScript qui appartient directement à l’objet. Par exemple, les instances JavaScript Array stockent le contenu du tableau dans un magasin de stockage, qui est un emplacement de mémoire distinct qui n’est pas inclus dans la taille superficielle du tableau.

Vous pouvez configurer la colonne Taille superficielle pour signaler la taille entière des objets, y compris la taille du magasin de stockage de l’objet.

Pour inclure la taille entière des objets dans la colonne Taille superficielle :

  1. Dans DevTools, cliquez sur le bouton Personnaliser et contrôler DevTools (icône Personnaliser et contrôler DevTools), puis cliquez sur Paramètres (icône Paramètres). Ou, pendant que DevTools a le focus, appuyez sur F1.

  2. Dans la section Expériences , cochez la case Dans les instantanés de tas, traitez la taille du magasin de stockage comme faisant partie de l’objet conteneur.

  3. Cliquez sur le bouton Fermer (x) de la page Paramètres , puis cliquez sur le bouton Recharger DevTools .

  4. Prenez un nouveau tas instantané. La colonne Taille superficielle inclut désormais la taille entière des objets :

    Colonne Taille superficielle d’un tas instantané

Filtrer les instantanés de tas par types de nœuds

Utilisez des filtres pour vous concentrer sur des parties spécifiques d’un tas instantané. Lorsque vous examinez tous les objets d’un tas instantané dans l’outil Mémoire, il peut être difficile de se concentrer sur des objets spécifiques ou de conserver des chemins d’accès.

Pour vous concentrer uniquement sur des types de nœuds spécifiques, utilisez le filtre Types de nœuds, en haut à droite. Par exemple, pour voir uniquement les tableaux et les objets de chaîne dans le tas instantané :

  1. Pour ouvrir le filtre Types de nœuds , cliquez sur Par défaut dans le coin supérieur droit.

  2. Sélectionnez les entrées Tableau et Chaîne .

    Le tas instantané est mis à jour pour afficher uniquement les objets de tableau et de chaîne :

    Types de nœuds dans un tas instantané dans l’outil Mémoire

Rechercher un objet spécifique

Pour rechercher un objet dans le tas collecté, vous pouvez effectuer une recherche à l’aide de Ctrl+F et donner l’ID de l’objet.

Découvrir les fuites DOM

L’outil Mémoire peut afficher les dépendances bidirectionnelles qui existent parfois entre les objets natifs du navigateur (nœuds DOM, règles CSS) et les objets JavaScript. Cela permet de détecter les fuites de mémoire qui se produisent en raison de nœuds DOM détachés oubliés qui restent en mémoire.

Considérez l’arborescence DOM suivante :

Sous-arborescences DOM

L’exemple de code suivant crée les variables treeRef JavaScript et leafRef, qui référencent deux des nœuds DOM dans l’arborescence :

// Get a reference to the #tree element.
const treeRef = document.querySelector("#tree");

// Get a reference to the #leaf element,
// which is a descendant of the #tree element.
const leafRef = document.querySelector("#leaf");

Dans l’exemple de code suivant, l’élément <div id="tree"> est supprimé de l’arborescence DOM :

// Remove the #tree element from the DOM.
document.body.removeChild(treeRef);

L’élément <div id="tree"> ne peut pas être récupéré par la mémoire, car la variable treeRef JavaScript existe toujours. La treeRef variable fait directement référence à l’élément <div id="tree"> . Dans l’exemple de code suivant, la treeRef variable est nullifiée :

// Remove the treeRef variable.
treeRef = null;

L’élément <div id="tree"> ne peut toujours pas être récupéré par la mémoire, car la variable leafRef JavaScript existe toujours. La leafRef.parentNode propriété fait référence à l’élément <div id="tree"> . Dans l’exemple de code suivant, la leafRef variable est nullifiée :

// Remove the leafRef variable.
leafRef = null;

À ce stade, l’élément <div id="tree"> peut être récupéré par la mémoire. leafRef Et treeRef doivent d’abord être nullifiés, pour que l’arborescence DOM entière sous l’élément <div id="tree"> soit récupérée par la mémoire.

Page web de démonstration : Exemple 6 : Fuite de nœuds DOM

Pour comprendre où les nœuds DOM peuvent fuir et comment détecter une telle fuite, ouvrez l’exemple de page web Exemple 6 : Fuite de nœuds DOM dans une nouvelle fenêtre ou un nouvel onglet.

Page web de démonstration : Exemple 9 : Fuites DOM plus importantes que prévu

Pour voir pourquoi une fuite DOM peut être plus grande que prévu, ouvrez l’exemple de page web Exemple 9 : Fuites DOM plus grandes que prévu dans une nouvelle fenêtre ou un nouvel onglet.

Analyser l’impact des fermetures sur la mémoire

Pour analyser l’impact des fermetures sur la mémoire, essayez cet exemple :

  1. Ouvrez la page web de démonstration Eval is evil dans une nouvelle fenêtre ou un nouvel onglet.

  2. Enregistrer un tas instantané.

  3. Dans la page web rendue, cliquez sur le bouton Fermetures avec eval .

  4. Enregistrez un deuxième tas instantané.

    Dans la barre latérale, le nombre sous la deuxième instantané doit être supérieur au nombre situé sous la première instantané. Cela indique que la page web utilise davantage de mémoire après avoir cliqué sur le bouton Fermetures avec eval .

  5. Dans le deuxième instantané de tas, remplacez l’affichage par Comparaison, puis comparez le deuxième tas instantané au premier instantané.

    La vue Comparaison montre que de nouvelles chaînes ont été créées dans le deuxième tas instantané :

    La vue Comparaison, montrant que de nouvelles chaînes ont été créées dans la deuxième instantané

  6. Dans la vue Comparaison, développez le constructeur (chaîne).

  7. Cliquez sur la première entrée (chaîne).

    La section Retainers est mise à jour et indique que la largeStr variable conserve la chaîne sélectionnée dans la vue Comparaison .

    L’entrée largeStr est automatiquement développée et indique que la variable est conservée par la eC fonction, qui est la fermeture où la variable est définie :

    Section Retainers, montrant que la chaîne est conservée par la fonction eC

Conseil : fonctions de nom pour différencier les fermetures d’un instantané

Pour faire facilement la distinction entre les fermetures JavaScript dans un tas instantané, donnez des noms à vos fonctions.

L’exemple suivant utilise une fonction sans nom pour retourner la largeStr variable :

function createLargeClosure() {
    const largeStr = 'x'.repeat(1000000).toLowerCase();

    // This function is unnamed.
    const lC = function() {
        return largeStr;
    };

    return lC;
}

L’exemple suivant nomme la fonction, ce qui facilite la distinction entre les fermetures dans le tas instantané :

function createLargeClosure() {
    const largeStr = 'x'.repeat(1000000).toLowerCase();

    // This function is named.
    const lC = function lC() {
        return largeStr;
    };

    return lC;
}

Enregistrer et exporter des chaînes à partir d’un tas instantané vers JSON

Lorsque vous prenez un tas instantané dans l’outil Mémoire, vous pouvez exporter tous les objets de chaîne du instantané vers un fichier JSON. Dans l’outil Mémoire , dans la section Constructeur , cliquez sur le bouton Enregistrer tout dans le fichier en regard de l’entrée (string) :

Enregistrer toutes les chaînes d’un tas instantané dans JSON

L’outil Mémoire exporte un fichier JSON qui contient tous les objets de chaîne du tas instantané :

Chaînes du tas instantané, dans le fichier JSON

Voir aussi

Remarque

Les parties de cette page sont des modifications basées sur le travail créé et partagé par Google et utilisées conformément aux termes décrits dans la licence internationale Creative Commons Attribution 4.0. La page d’origine est disponible ici et est créée par Meggin Kearney (Rédacteur technique).

Licence Creative Commons Cette œuvre est concédée sous licence creative commons attribution 4.0 international.