Découvrez comment enregistrer des instantanés de segments de mémoire avec Mémoire > Profils > Instantané de tas de mémoire et recherchez les fuites de mémoire.
Le profileur de segments de mémoire affiche la répartition de la mémoire en fonction des objets JavaScript de votre page et des nœuds DOM associés. Utilisez-le pour prendre des instantanés de segments de mémoire JavaScript, analyser des graphiques de mémoire, comparer des instantanés et détecter des fuites de mémoire. Pour en savoir plus, consultez Arbre de conservation des objets.
Prendre un instantané
Pour prendre un instantané de segment de mémoire, procédez comme suit:
- Sur une page que vous souhaitez profiler, ouvrez les outils pour les développeurs, puis accédez au panneau Mémoire.
- Sélectionnez le type de profilage Instantané de tas , puis sélectionnez une instance de VM JavaScript, puis cliquez sur Prendre un instantané.
Lorsque le panneau Memory (Mémoire) charge et analyse l'instantané, la taille totale des objets JavaScript accessibles est indiquée sous le titre de l'instantané dans la section SNAPSHOTS HEAP.
Les instantanés n'affichent que les objets du graphique de mémoire qui sont accessibles depuis l'objet global. La création d'un instantané commence toujours par la récupération de mémoire.
Effacer les instantanés
Pour supprimer tous les instantanés, cliquez sur
Effacer tous les profils:Afficher les instantanés
Pour inspecter des instantanés sous différents angles à des fins différentes, sélectionnez l'une des vues dans le menu déroulant situé en haut de l'écran:
Afficher | Contenu | Objectif |
---|---|---|
Résumé | Objets regroupés par nom de constructeur. | Utilisez-la pour rechercher des objets et leur utilisation de mémoire en fonction de leur type. Utile pour suivre les fuites DOM. |
Comparatif | Différences entre deux instantanés. | Utilisez-le pour comparer deux (ou plusieurs) instantanés, avant et après une opération. Vérifiez la présence et la cause d'une fuite de mémoire en inspectant le delta dans la mémoire libérée et le nombre de références. |
Structuration | Contenu du tas de mémoire | Fournit une meilleure vue de la structure des objets et permet d'analyser les objets référencés dans l'espace de noms global (fenêtre) pour trouver ce qui les conserve. Utilisez-le pour analyser les routes fermées et plonger dans vos objets à faible niveau. |
Statistiques | Graphique à secteurs de l'allocation de mémoire | Consultez la taille réelle des parties de mémoire allouées au code, aux chaînes, aux tableaux JavaScript, aux tableaux typés et aux objets système. |
Affichage récapitulatif
Initialement, un instantané de segment de mémoire s'ouvre dans la vue Résumé qui répertorie les Constructeurs dans une colonne. Vous pouvez développer les constructeurs pour voir les objets qu'ils ont instanciés.
Pour filtrer les constructeurs non pertinents, saisissez le nom que vous souhaitez inspecter dans le filtre de classe en haut de la vue Summary (Résumé).
Les chiffres associés aux noms des constructeurs indiquent le nombre total d'objets créés avec le constructeur. La vue Récapitulatif affiche également les colonnes suivantes :
- Distance indique la distance jusqu'à la racine en utilisant le chemin simple le plus court de nœuds.
- Taille peu profonde indique la somme des tailles peu profondes de tous les objets créés par un certain constructeur. La taille superficielle correspond à la taille de la mémoire détenue par un objet lui-même. En règle générale, les tableaux et les chaînes ont des tailles superficielles plus grandes. Consultez également la section Tailles des objets.
- Taille conservée indique la taille conservée maximale parmi le même ensemble d'objets. La taille conservée est la taille de la mémoire que vous pouvez libérer en supprimant un objet et en rendant ses dépendances inaccessibles. Consultez également la section Tailles d'objet.
Lorsque vous développez un constructeur, la vue Summary (Résumé) affiche toutes ses instances. Chaque instance reçoit une répartition de ses tailles superficielles et conservées dans les colonnes correspondantes. Le nombre situé après le caractère @
correspond à l'identifiant unique de l'objet. Il vous permet de comparer les instantanés de tas de mémoire par objet.
Filtres du constructeur
La vue Summary (Résumé) vous permet de filtrer les constructeurs en fonction des cas courants d'utilisation inefficace de la mémoire.
Pour utiliser ces filtres, sélectionnez l'une des options suivantes dans le menu déroulant situé tout à droite de la barre d'action:
- Tous les objets: tous les objets capturés par l'instantané actuel. Défini par défaut.
- Objets alloués avant l'instantané 1: objets créés et conservés en mémoire avant la prise du premier instantané.
- Objets alloués entre les instantanés 1 et les instantanés 2: visualisez la différence d'objets entre l'instantané le plus récent et l'instantané précédent. Chaque nouvel instantané ajoute un incrément de ce filtre à la liste déroulante.
- Chaînes en double: valeurs de chaîne stockées plusieurs fois en mémoire.
- Objets conservés par les nœuds dissociés : objets conservés, car un nœud DOM dissocié les référence.
- Objets conservés par la console des outils de développement : objets conservés en mémoire, car ils ont été évalués ou avec lesquels vous avez interagi via la console des outils de développement.
Entrées spéciales dans le résumé
En plus de procéder au regroupement par constructeur, la vue Summary regroupe également les objets selon les critères suivants:
- Des fonctions intégrées telles que
Array
ouObject
- Éléments HTML regroupés en fonction de leurs balises (par exemple,
<div>
,<a>
,<img>
, etc.). - Fonctions que vous avez définies dans votre code
- Catégories spéciales qui ne sont pas basées sur des constructeurs.
(array)
Cette catégorie comprend divers objets internes ressemblant à des tableaux qui ne correspondent pas directement aux objets visibles dans JavaScript.
Par exemple, le contenu des objets JavaScript Array
est stocké dans un objet interne secondaire nommé (object elements)[]
pour faciliter le redimensionnement. De même, les propriétés nommées dans les objets JavaScript sont souvent stockées dans des objets internes secondaires nommés (object properties)[]
, qui sont également répertoriés dans la catégorie (array)
.
(compiled code)
Cette catégorie inclut les données internes dont V8 a besoin pour exécuter des fonctions définies par JavaScript ou WebAssembly. Chaque fonction peut être représentée de différentes manières, de petite et lente à grande et rapide.
V8 gère automatiquement l'utilisation de la mémoire dans cette catégorie. Si une fonction s'exécute plusieurs fois, V8 utilise plus de mémoire pour qu'elle puisse s'exécuter plus rapidement. Si une fonction ne s'exécute pas depuis un certain temps, V8 peut effacer les données internes de cette fonction.
(concatenated string)
Lorsque V8 concatène deux chaînes, comme avec l'opérateur JavaScript +
, il peut choisir de représenter le résultat en interne sous la forme d'une "chaîne concaténée", également appelée structure de données Rope.
Plutôt que de copier tous les caractères des deux chaînes sources dans une nouvelle chaîne, V8 alloue un petit objet avec des champs internes appelés first
et second
, qui pointent vers les deux chaînes sources. Cela permet à V8 d'économiser du temps et de la mémoire. Du point de vue du code JavaScript, il ne s'agit que de chaînes normales, qui se comportent comme n'importe quelle autre chaîne.
InternalNode
Cette catégorie représente les objets alloués en dehors de V8, tels que les objets C++ définis par Blink.
Pour afficher les noms des classes C++, utilisez Chrome for Testing et procédez comme suit:
- Ouvrez les outils de développement et activez Settings > Tests > Afficher l'option permettant d'exposer les éléments internes dans les instantanés de segments de mémoire
- Ouvrez le panneau Memory (Mémoire), sélectionnez Instantané de tas de mémoire, puis activez Exposer les composants internes (inclut des informations supplémentaires spécifiques à l'implémentation).
- Reproduisez le problème qui a entraîné la conservation d'une grande quantité de mémoire par
InternalNode
. - Prendre un instantané du tas de mémoire Dans cet instantané, les objets portent des noms de classe C++ au lieu de
InternalNode
.
(object shape)
Comme décrit dans Propriétés rapides dans V8, V8 suit les classes masquées (ou formes) afin que plusieurs objets ayant les mêmes propriétés dans le même ordre puissent être représentés efficacement. Cette catégorie contient ces classes masquées, appelées system / Map
(sans rapport avec JavaScript Map
) et les données associées.
(sliced string)
Lorsque V8 doit prendre une sous-chaîne, par exemple lorsque le code JavaScript appelle String.prototype.substring()
, V8 peut choisir d'allouer 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.
Du point de vue du code JavaScript, il ne s'agit que de chaînes normales qui se comportent comme n'importe quelle autre chaîne. Si une chaîne segmentée conserve une grande quantité de mémoire, il se peut que le programme ait déclenché le problème 2869 et qu'il soit utile de prendre des mesures délibérées pour "aplatir". la chaîne segmentée.
system / Context
Les objets internes de type system / Context
contiennent des variables locales provenant d'une fermeture, c'est-à-dire un champ d'application JavaScript auquel une fonction imbriquée peut accéder.
Chaque instance de fonction contient un pointeur interne vers la Context
dans laquelle elle s'exécute, afin de pouvoir accéder à ces variables. Même si les objets Context
ne sont pas directement visibles à partir de JavaScript, vous pouvez les contrôler directement.
(system)
Cette catégorie contient divers objets internes qui n'ont pas (encore) été catégorisés de manière plus pertinente.
Comparaison
La vue Comparison (Comparaison) vous permet de trouver les objets divulgués en comparant plusieurs instantanés entre eux. Par exemple, le fait d'effectuer une action et de l'inverser, comme ouvrir un document et le fermer, ne doit pas laisser d'objets supplémentaires derrière.
Pour vérifier qu'une opération donnée ne crée pas de fuites:
- Prenez un instantané de segment de mémoire avant d'effectuer une opération.
- Effectuez une opération. En d'autres termes, interagissez avec une page d'une manière qui, selon vous, peut être à l'origine d'une fuite.
- Effectuez une opération inverse. Autrement dit, faites l'interaction opposée et répétez l'opération plusieurs fois.
- Prenez un deuxième instantané de segment de mémoire et passez à l'affichage Comparison (Comparaison) pour le comparer à Instantané 1.
La vue Comparison (Comparaison) montre la différence entre deux instantanés. Pour développer un total les instances d'objets d'entrée, ajoutées et supprimées sont affichées:
Vue de l'isolement
La vue Confinement est une vue plongeante. de la structure des objets de votre application. Il vous permet d'examiner les fermetures de fonctions, d'observer les objets internes de VM qui forment ensemble vos objets JavaScript et de comprendre la quantité de mémoire utilisée par votre application à très bas niveau.
La vue fournit plusieurs points d'entrée:
- Objets DOMWindow Objets globaux pour le code JavaScript.
- Racines de récupération de mémoire : Racines GC utilisées par le garbage collector de la VM. Les racines de récupération de mémoire peuvent être constituées de mappages d'objets intégrés, de tables de symboles, de piles de threads de VM, de caches de compilation, de champs d'application de handle et de identifiants globaux.
- Objets natifs : Objets du navigateur "poussés" dans la machine virtuelle JavaScript pour permettre l'automatisation, par exemple, les nœuds DOM et les règles CSS.
Section "Personnes ayant conservé des données"
La section Éléments de conservation en bas du panneau Mémoire affiche les objets qui pointent vers l'objet sélectionné dans la vue. Le panneau Mémoire met à jour la section Conservateurs lorsque vous sélectionnez un autre objet dans l'une des vues, à l'exception de Statistiques.
Dans cet exemple, la chaîne sélectionnée est conservée par la propriété x
d'une instance Item
.
Ignorer les éléments de conservation
Vous pouvez masquer les éléments de conservation pour voir s'il y a d'autres objets qui conservent l'élément sélectionné. Avec cette option, vous n'avez pas besoin de supprimer d'abord ce retenant du code, puis de refaire l'instantané de la pile.
Pour masquer un appareil de retenue, effectuez un clic droit, puis sélectionnez Ignorer cet appareil de retenue. Les éléments de conservation ignorés sont marqués comme ignored
dans la colonne Distance. Pour ne plus ignorer tous les retiens, cliquez sur Restore ignored retainers (Rétablir les retiens ignorés) dans la barre d'action en haut de l'écran.
Trouver un objet spécifique
Pour trouver un objet dans le tas de mémoire collecté, vous pouvez effectuer une recherche à l'aide de Ctrl + F et saisir l'ID de l'objet.
Nommer les fonctions pour distinguer les routes fermées
Il est très utile de nommer les fonctions afin de pouvoir faire la distinction entre les routes fermées dans l'instantané.
Par exemple, le code suivant n'utilise pas de fonctions nommées:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function() { // this is NOT a named function
return largeStr;
};
return lC;
}
Dans cet exemple:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function lC() { // this IS a named function
return largeStr;
};
return lC;
}
Identifier les fuites DOM
Le profileur de segments de mémoire peut refléter les dépendances bidirectionnelles entre les objets natifs du navigateur (nœuds DOM et règles CSS) et les objets JavaScript. Cela permet d'identifier des fuites autrement invisibles qui se produisent en raison de sous-arborescences DOM dissociées oubliées qui flottent.
Les fuites DOM peuvent être plus importantes que vous ne le pensez. Voici un exemple. Quand la corbeille #tree
est-elle récupérée ?
var select = document.querySelector;
var treeRef = select("#tree");
var leafRef = select("#leaf");
var body = select("body");
body.removeChild(treeRef);
//#tree can't be GC yet due to treeRef
treeRef = null;
//#tree can't be GC yet due to indirect
//reference from leafRef
leafRef = null;
//#NOW #tree can be garbage collected
#leaf
conserve une référence à son parent (parentNode
) et jusqu'à #tree
de manière récursive. Ainsi,
Lorsque la valeur nulle de leafRef
est nulle, l'arborescence entière sous #tree
est candidate à la récupération de mémoire.