Découvrez comment utiliser Chrome et les outils de développement pour identifier les problèmes de mémoire qui affectent les performances des pages, y compris les fuites de mémoire, l'encombrement de la mémoire et les récupérations de mémoire fréquentes.
Résumé
- Découvrez la quantité de mémoire utilisée par votre page à l'aide du Gestionnaire des tâches de Chrome.
- Visualisez l'utilisation de la mémoire au fil du temps avec les enregistrements de la chronologie.
- Identifiez les arbres DOM détachés (une cause courante de fuites de mémoire) avec les instantanés de segment de mémoire.
- Découvrez quand une nouvelle mémoire est allouée dans votre tas de mémoire JS grâce aux enregistrements de la chronologie d'allocation.
- Identifiez les éléments dissociés conservés par une référence JavaScript.
Présentation
Dans l'esprit du modèle de performances RAIL, vos efforts d'optimisation des performances doivent se concentrer sur vos utilisateurs.
Les problèmes de mémoire sont importants, car ils sont souvent perceptibles par les utilisateurs. Les utilisateurs peuvent percevoir les problèmes de mémoire de différentes manières :
- Les performances d'une page se dégradent progressivement au fil du temps. Il s'agit peut-être d'un symptôme de fuite de mémoire. Une fuite de mémoire se produit lorsqu'un bug sur la page entraîne une utilisation progressive de plus en plus importante de la mémoire au fil du temps.
- Les performances d'une page sont constamment mauvaises. Il s'agit peut-être d'un symptôme de gonflement de la mémoire. On parle de gonflement de la mémoire lorsqu'une page utilise plus de mémoire que nécessaire pour une vitesse de page optimale.
- Les performances d'une page sont retardées ou semblent s'interrompre fréquemment. Cela peut être le symptôme de récupérations de mémoire fréquentes. La récupération de mémoire est le processus par lequel le navigateur récupère de la mémoire. Le navigateur décide quand cela se produit. Pendant les collectes, l'exécution de tous les scripts est suspendue. Si le navigateur effectue de nombreuses opérations de récupération de mémoire, l'exécution du script sera souvent mise en pause.
Surcharge de mémoire : à partir de quand est-ce "trop" ?
Une fuite de mémoire est facile à définir. Si un site utilise de plus en plus de mémoire, cela signifie qu'il y a une fuite. Mais l'augmentation de la mémoire est un peu plus difficile à cerner. Qu'entend-on par "utiliser trop de mémoire" ?
Il n'y a pas de chiffres précis, car les différents appareils et navigateurs ont des capacités différentes. Une page qui s'exécute sans problème sur un smartphone haut de gamme peut planter sur un smartphone d'entrée de gamme.
L'essentiel est d'utiliser le modèle RAIL et de vous concentrer sur vos utilisateurs. Découvrez quels appareils sont populaires auprès de vos utilisateurs, puis testez votre page sur ces appareils. Si l'expérience est systématiquement mauvaise, il est possible que la page dépasse les capacités de mémoire de ces appareils.
Surveiller l'utilisation de la mémoire en temps réel avec le Gestionnaire de tâches Chrome
Utilisez le Gestionnaire des tâches de Chrome comme point de départ pour examiner votre problème de mémoire. Le Gestionnaire des tâches est un outil de surveillance en temps réel qui vous indique la quantité de mémoire utilisée par une page.
Appuyez sur Maj+Échap ou accédez au menu principal de Chrome, puis sélectionnez Plus d'outils > Gestionnaire des tâches pour ouvrir le gestionnaire des tâches.

Effectuez un clic droit sur l'en-tête du tableau du gestionnaire des tâches, puis activez Mémoire JavaScript.

Ces deux colonnes vous fournissent des informations différentes sur la façon dont votre page utilise la mémoire :
- La colonne Espace mémoire utilisé représente la mémoire de l'OS. Les nœuds DOM sont stockés dans la mémoire de l'OS. Si cette valeur augmente, des nœuds DOM sont créés.
La colonne Mémoire JavaScript représente le tas de mémoire JS. Cette colonne contient deux valeurs. La valeur qui vous intéresse est le nombre en direct (le nombre entre parenthèses). Le nombre d'objets actifs représente la quantité de mémoire utilisée par les objets accessibles sur votre page. Si ce nombre augmente, cela signifie que de nouveaux objets sont créés ou que les objets existants augmentent.

Visualiser les fuites de mémoire avec les enregistrements de performances
Vous pouvez également utiliser le panneau Performance comme autre point de départ de votre investigation. Le panneau "Performances" vous aide à visualiser l'utilisation de la mémoire d'une page au fil du temps.
- Ouvrez le panneau Performances dans les outils de développement.
- Cochez la case Mémoire.
- Créer un enregistrement
Pour illustrer les enregistrements de mémoire de l'onglet Performance, prenons le code suivant :
var x = [];
function grow() {
for (var i = 0; i < 10000; i++) {
document.body.appendChild(document.createElement('div'));
}
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
Chaque fois que l'utilisateur appuie sur le bouton référencé dans le code, 10 000 nœuds div sont ajoutés au corps du document, et une chaîne d'un million de caractères x est insérée dans le tableau x.
L'exécution de ce code produit un enregistrement de chronologie semblable à la capture d'écran suivante :

Tout d'abord, une explication de l'interface utilisateur. Le graphique HEAP du volet Overview (sous NET) représente le tas JS. Le volet Compteur se trouve sous le volet Présentation. Vous pouvez voir l'utilisation de la mémoire répartie par tas de mémoire JS (identique au graphique TAS DE MÉMOIRE du volet Présentation), documents, nœuds DOM, écouteurs et mémoire GPU. Si vous décochez une case, elle est masquée dans le graphique.
Maintenant, une analyse du code par rapport à la capture d'écran. Si vous regardez le compteur de nœuds (le graphique vert), vous pouvez voir qu'il correspond parfaitement au code. Le nombre de nœuds augmente par étapes distinctes. Vous pouvez supposer que chaque augmentation du nombre de nœuds correspond à un appel à grow(). Le graphique du tas JS (le graphique bleu) n'est pas aussi simple. Conformément aux bonnes pratiques, la première baisse est en fait une récupération de mémoire forcée (obtenue en appuyant sur le bouton Collect garbage (Récupérer la mémoire)). Au fur et à mesure de l'enregistrement, vous pouvez voir que la taille du tas JS augmente. C'est naturel et attendu : le code JavaScript crée les nœuds DOM à chaque clic sur le bouton et effectue beaucoup de travail lorsqu'il crée la chaîne d'un million de caractères. Le point essentiel ici est que le tas JS se termine plus haut qu'il n'a commencé (le "début" étant ici le point après le nettoyage forcé de la mémoire). Dans le monde réel, si vous observiez ce schéma d'augmentation de la taille du tas de mémoire JS ou de la taille des nœuds, cela pourrait signifier une fuite de mémoire.
Détecter les fuites de mémoire de l'arborescence DOM détachée avec les instantanés de segment de mémoire
Un nœud DOM ne peut être récupéré que s'il n'existe aucune référence à celui-ci dans l'arborescence DOM de la page ou dans le code JavaScript. Un nœud est dit "dissocié" lorsqu'il est supprimé de l'arborescence DOM, mais qu'un code JavaScript y fait toujours référence. Les nœuds DOM dissociés sont une cause fréquente de fuites de mémoire. Cette section vous explique comment utiliser les profileurs de segments de mémoire des outils de développement pour identifier les nœuds détachés.
Voici un exemple simple de nœuds DOM dissociés.
var detachedTree;
function create() {
var ul = document.createElement('ul');
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
ul.appendChild(li);
}
detachedTree = ul;
}
document.getElementById('create').addEventListener('click', create);
En cliquant sur le bouton référencé dans le code, vous créez un nœud ul avec dix enfants li. Ces nœuds sont référencés par le code, mais n'existent pas dans l'arborescence DOM. Ils sont donc détachés.
Les instantanés de segment de mémoire sont un moyen d'identifier les nœuds détachés. Comme leur nom l'indique, les instantanés de segment de mémoire vous montrent comment la mémoire est répartie entre les objets JS et les nœuds DOM de votre page au moment de l'instantané.
Pour créer un instantané, ouvrez les outils de développement et accédez au panneau Memory (Mémoire), sélectionnez la case d'option Heap Snapshot (Instantané de segment de mémoire), puis appuyez sur le bouton Take snapshot (Prendre un instantané).

Le traitement et le chargement de l'instantané peuvent prendre un certain temps. Une fois l'opération terminée, sélectionnez l'instantané dans le panneau de gauche (intitulé Instantanés de segment de mémoire).
Saisissez Detached dans le champ de saisie Filtre de classe pour rechercher les arbres DOM dissociés.

Développez les chevrons pour examiner une arborescence dissociée.

Cliquez sur un nœud pour l'examiner plus en détail. Dans le volet Objets, vous pouvez afficher plus d'informations sur le code qui le référence. Par exemple, dans la capture d'écran suivante, vous pouvez voir que la variable detachedTree fait référence au nœud. Pour corriger cette fuite de mémoire particulière, vous devez étudier le code qui utilise detachedTree et vous assurer qu'il supprime sa référence au nœud lorsqu'il n'est plus nécessaire.

Identifier les fuites de mémoire du tas de mémoire JS avec les chronologies d'allocation
La chronologie d'allocation est un autre outil qui peut vous aider à détecter les fuites de mémoire dans votre tas JS.
Pour illustrer la chronologie d'allocation, prenons le code suivant :
var x = [];
function grow() {
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
Chaque fois que l'utilisateur appuie sur le bouton référencé dans le code, une chaîne d'un million de caractères est ajoutée au tableau x.
Pour enregistrer une chronologie d'allocation, ouvrez les outils de développement, accédez au panneau Mémoire, sélectionnez la case d'option Allocations sur la chronologie, appuyez sur le bouton Enregistrer, effectuez l'action qui, selon vous, est à l'origine de la fuite de mémoire, puis appuyez sur le bouton Arrêter l'enregistrement lorsque vous avez terminé.
Pendant l'enregistrement, vérifiez si des barres bleues s'affichent dans la chronologie d'allocation, comme dans la capture d'écran suivante.

Ces barres bleues représentent les nouvelles allocations de mémoire. Ces nouvelles allocations de mémoire sont vos candidates aux fuites de mémoire. Vous pouvez zoomer sur une barre pour filtrer le volet Constructeur afin de n'afficher que les objets alloués pendant la période spécifiée.

Développez l'objet et cliquez sur sa valeur pour afficher plus de détails dans le volet Objet. Par exemple, dans la capture d'écran ci-dessous, en affichant les détails de l'objet qui vient d'être alloué, vous pouvez voir qu'il a été alloué à la variable x dans le champ d'application Window.

Examiner l'allocation de mémoire par fonction
Utilisez le type de profil Échantillonnage d'allocation dans le panneau Mémoire pour afficher l'allocation de mémoire par fonction JavaScript.

- Sélectionnez la case d'option Échantillonnage d'allocation. Si un worker est présent sur la page, vous pouvez le sélectionner comme cible de profilage dans la fenêtre Sélectionner l'instance de VM JavaScript.
- Appuyez sur le bouton Démarrer.
- Effectuez les actions sur la page que vous souhaitez examiner.
- Appuyez sur le bouton Arrêter lorsque vous avez terminé toutes vos actions.
Les outils de développement affichent une répartition de l'allocation de mémoire par fonction. La vue par défaut est Heavy (Bottom Up) (Lourd (ascendant)), qui affiche en haut les fonctions qui ont alloué le plus de mémoire.

Identifier les objets conservés par une référence JS
Le profil Éléments dissociés affiche les éléments dissociés qui persistent, car ils sont référencés par du code JavaScript.
Enregistrez un profil Éléments dissociés pour afficher les nœuds HTML exacts et le nombre de nœuds.

Détecter les récupérations de mémoire fréquentes
Si votre page semble s'interrompre fréquemment, vous rencontrez peut-être des problèmes de récupération de mémoire.
Vous pouvez utiliser le gestionnaire de tâches de Chrome ou les enregistrements de mémoire de la chronologie pour repérer les collectes de mémoire fréquentes. Dans le gestionnaire de tâches, les valeurs Mémoire ou Mémoire JavaScript qui augmentent et diminuent fréquemment représentent des récupérations de mémoire fréquentes. Dans les enregistrements de la chronologie, les graphiques de tas JS ou de nombre de nœuds qui augmentent et diminuent fréquemment indiquent des collectes de mémoire fréquentes.
Une fois que vous avez identifié le problème, vous pouvez utiliser un enregistrement de la chronologie d'allocation pour identifier l'emplacement de l'allocation de mémoire et les fonctions à l'origine des allocations.