Résoudre les problèmes de mémoire

Découvrez comment utiliser Microsoft Edge et DevTools pour rechercher les problèmes de mémoire qui affectent les performances des pages, notamment les fuites de mémoire, les surcharges de mémoire et les nettoyages de mémoire fréquents.

  • Découvrez la quantité de mémoire que votre page utilise actuellement avec le Gestionnaire des tâches du navigateur Microsoft Edge.
  • Visualisez l’utilisation de la mémoire au fil du temps avec l’outil Mémoire .
  • Identifiez les arborescences DOM détachées (une cause courante des fuites de mémoire) avec le tas instantané.
  • Découvrez quand une nouvelle mémoire est allouée dans votre tas JavaScript (tas JS) avec l’instrumentation d’allocation sur chronologie.

Voir aussi Déboguer les fuites de mémoire DOM avec l’outil Éléments détachés.

Vue d'ensemble

Dans l’esprit du modèle de performance RAIL , vos efforts en matière de performances doivent être axés 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 des manières suivantes :

  • Les performances d’une page s’aggravent progressivement au fil du temps. Il s’agit peut-être d’un symptôme d’une fuite de mémoire. Une fuite de mémoire se produit lorsqu’un bogue dans la page entraîne l’utilisation progressive de la mémoire par la page au fil du temps.

  • Les performances d’une page sont constamment mauvaises. C’est peut-être un symptôme d’un ballonnement de la mémoire. L’hypertrophie de la mémoire se produit 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. Il s’agit peut-être d’un symptôme de nettoyages de la mémoire fréquents. Le garbage collection est le moment où le navigateur récupère de la mémoire. Le navigateur décide quand cela se produit. Pendant les collections, tout le script en cours d’exécution est suspendu. Par conséquent, si le navigateur collecte beaucoup la mémoire, l’exécution du script va être beaucoup suspendue.

Ballonnement de la mémoire : combien est « trop » ?

Une fuite de mémoire est facile à définir. Si un site utilise progressivement de plus en plus de mémoire, vous avez une fuite. Mais le ballonnement de la mémoire est un peu plus difficile à épingler. Qu’est-ce qui peut être considéré comme « utiliser trop de mémoire » ?

Il n’y a pas de nombres durs ici, car différents appareils et navigateurs ont des fonctionnalités différentes. La même page qui fonctionne en douceur sur un smartphone haut de gamme peut se bloquer sur un smartphone bas de gamme.

La clé ici 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 incorrecte, la page peut dépasser les capacités de mémoire de ces appareils.

Surveiller l’utilisation de la mémoire en temps réel avec le Gestionnaire des tâches du navigateur Microsoft Edge

Utilisez le Gestionnaire des tâches du navigateur Microsoft Edge comme point de départ pour l’examen des problèmes de mémoire. Le Gestionnaire des tâches du navigateur Microsoft Edge est un moniteur en temps réel qui vous indique la quantité de mémoire qu’une page utilise actuellement.

  1. Appuyez sur Maj+Échap ou accédez au menu Microsoft Edge main et sélectionnez Autres outilsGestionnaire des tâches> du navigateur pour ouvrir le Gestionnaire des tâches du navigateur Microsoft Edge.

    Ouverture du Gestionnaire des tâches du navigateur Microsoft Edge

  2. Cliquez avec le bouton droit sur l’en-tête de table du Gestionnaire des tâches du navigateur Microsoft Edge, puis activez la mémoire JavaScript.

    Activation de la mémoire JavaScript

Ces deux colonnes vous indiquent différentes choses sur la façon dont votre page utilise la mémoire :

  • La colonne Mémoire représente la mémoire native. Les nœuds DOM sont stockés dans la mémoire native. Si cette valeur augmente, les nœuds DOM sont créés.

  • La colonne Mémoire JavaScript représente le tas JS. Cette colonne contient deux valeurs. La valeur qui vous intéresse est le nombre en direct (le nombre entre parenthèses). Le nombre dynamique représente la quantité de mémoire utilisée par les objets accessibles sur votre page. Si ce nombre augmente, soit de nouveaux objets sont créés, soit les objets existants augmentent.

Visualiser les fuites de mémoire avec l’outil Performance

Vous pouvez également utiliser l’outil Performance comme autre point de départ dans votre investigation. L’outil Performance vous permet de visualiser l’utilisation de la mémoire d’une page au fil du temps.

  1. Dans DevTools, ouvrez l’outil Performance .

  2. Cochez la case Mémoire .

  3. Effectuez un enregistrement.

Il est recommandé de commencer et de terminer votre enregistrement avec un garbage collection forcé. Pour forcer le garbage collection, cliquez sur le bouton garbageforce collection lors de l’enregistrement.

Pour illustrer les enregistrements de mémoire, considérez 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 clique sur le bouton référencé dans le code, 10 000 div nœuds sont ajoutés au corps du document et une chaîne de 1 000 000 x caractères est envoyée au x tableau. L’exécution de l’exemple de code précédent produit un enregistrement dans l’outil Performance comme la figure suivante :

Croissance simple

Tout d’abord, une explication de l’interface utilisateur. Le graphe HEAP dans le volet Vue d’ensemble (sous NET) représente le tas JS. Sous le volet Vue d’ensemble se trouve le volet Compteur . L’utilisation de la mémoire est répartie par segment JS (identique au graphe HEAP dans le volet Vue d’ensemble ), documents, nœuds DOM, écouteurs et mémoire GPU. Décochez une case pour la masquer du graphique.

Maintenant, une analyse du code par rapport à la figure précédente. Si vous examinez le compteur de nœud (le graphe vert), il correspond proprement au code. Le nombre de nœuds augmente en étapes discrètes. Vous pouvez présumer que chaque augmentation du nombre de nœuds est un appel à grow().

Le graphique du tas JS (le graphe bleu) n’est pas aussi simple. Conformément aux bonnes pratiques, le premier creux est en fait un garbage collection forcé (cliquez sur le bouton garbagecollection ).

À mesure que l’enregistrement progresse, les pics de taille de tas JS s’affichent. Ceci est naturel et attendu : le code JavaScript crée les nœuds DOM sur chaque bouton sur lequel vous cliquez et fait beaucoup de travail quand il crée la chaîne d’un million de caractères.

La chose clé ici est le fait que le tas JS se termine plus haut qu’il n’a commencé (le « début » ici étant le point après le garbage collection forcé). Dans le monde réel, si vous voyiez ce modèle d’augmentation de la taille du tas JS ou de la taille des nœuds, cela indiquerait potentiellement une fuite de mémoire.

Découvrir les fuites de mémoire de l’arborescence DOM détachée avec les instantanés de tas

Un nœud DOM n’est collecté que lorsqu’il n’y a aucune référence au nœud à partir de l’arborescence DOM ou du code JavaScript en cours d’exécution sur la page. Un nœud est dit « détaché » lorsqu’il est supprimé de l’arborescence DOM, mais certains éléments JavaScript y font toujours référence. Les nœuds DOM détachés sont une cause courante des fuites de mémoire.

Cette section vous apprend à utiliser les profileurs de tas dans DevTools pour identifier les nœuds détachés.

Voici un exemple simple de nœuds DOM détaché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);

Le fait de cliquer sur le bouton référencé dans le code crée un ul nœud avec dix li enfants. Les nœuds sont référencés par le code, mais ils n’existent pas dans l’arborescence DOM, de sorte que chaque nœud est détaché.

Les instantanés de tas sont un moyen d’identifier les nœuds détachés. Comme leur nom l’indique, les instantanés de tas vous montrent comment la mémoire est distribuée entre les objets JS et les nœuds DOM de votre page au moment de l’instantané.

Pour créer un instantané :

  1. Ouvrez DevTools et accédez à l’outil Mémoire .

  2. Cliquez sur la case d’option Tas instantané, puis sur le bouton Prendre instantané en bas de l’outil.

    Prise d’un tas instantané

    Le traitement et le chargement des instantané peuvent prendre un certain temps.

  3. Une fois le instantané terminé, sélectionnez-le dans le volet gauche (il s’appelle HEAP SNAPSHOTS).

  4. Dans la zone de texte Filtre de classe, tapez Detached, pour rechercher des arborescences DOM détachées :

    Filtrage pour les nœuds détachés

  5. Développez les carats pour examiner une arborescence détachée :

    Examen de l’arborescence détachée

  6. Cliquez sur un nœud pour l’examiner plus en détail.

    Dans le volet Objets , vous pouvez voir plus d’informations sur le code qui fait référence au nœud. Par exemple, dans la figure suivante, la detachedTree variable fait référence au nœud.

  7. Pour corriger la fuite de mémoire particulière, étudiez le code qui utilise la detachedTree variable et assurez-vous que la référence au nœud est supprimée lorsqu’elle n’est plus nécessaire.

Examen d’un nœud

Identifier les fuites de mémoire du tas JS avec l’instrumentation d’allocation sur chronologie

L’instrumentation d’allocation sur chronologie est un autre outil qui peut vous aider à localiser les fuites de mémoire dans votre tas JS.

Illustrez l’instrumentation d’allocation sur chronologie à l’aide du code suivant :

var x = [];
function grow() {
    x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);

Chaque fois que l’utilisateur clique sur le bouton référencé dans le code, une chaîne d’un million de caractères est ajoutée au x tableau.

Pour enregistrer une instrumentation d’allocation sur chronologie :

  1. Ouvrez DevTools, puis sélectionnez l’outil Mémoire .

  2. Cliquez sur la case d’option Instrumentation d’allocation sur chronologie, puis cliquez sur le bouton Démarrer.

  3. Effectuez l’action que vous soupçonnez d’être à l’origine de la fuite de mémoire.

  4. Lorsque vous avez terminé, cliquez sur le bouton Arrêter l’enregistrement du profil de tasarrêter l’enregistrement .

  5. Lorsque vous enregistrez, notez si des barres bleues s’affichent sur l’instrumentation d’allocation sur le chronologie, comme dans la figure suivante :

    Nouvelles allocations

    Ces barres bleues représentent de nouvelles allocations de mémoire. Ces nouvelles allocations de mémoire sont vos candidats aux fuites de mémoire.

  6. Effectuez un zoom sur une barre pour filtrer le volet Constructeur afin d’afficher uniquement les objets qui ont été alloués pendant la période spécifiée.

    Chronologie d’allocation avec zoom

  7. Développez l’objet et sélectionnez la valeur pour afficher plus de détails dans le volet Objet .

    Par exemple, dans la figure suivante, dans les détails de l’objet nouvellement alloué indique qu’il a été alloué à la x variable dans l’étendue Window :

Détails de l’objet

Examiner l’allocation de mémoire par fonction

Utilisez le type de profilage d’échantillonnage d’allocation pour afficher l’allocation de mémoire par fonction JavaScript.

Échantillonnage d’allocation d’enregistrements

  1. Cliquez sur la case d’option Échantillonnage d’allocation .

  2. S’il existe un worker sur la page, vous pouvez le sélectionner comme cible de profilage, en utilisant le menu déroulant en regard du bouton Démarrer .

  3. Cliquez sur le bouton Démarrer .

  4. Sur la page web, effectuez les actions que vous souhaitez examiner.

  5. Cliquez sur le bouton Arrêter lorsque vous avez terminé toutes vos actions.

DevTools vous montre une répartition de l’allocation de mémoire par fonction. L’affichage par défaut est Heavy (Bottom Up), qui affiche les fonctions qui ont alloué le plus de mémoire en haut.

Échantillonnage d’allocation

Réduire la mémoire avec des paramètres supplémentaires pour l’échantillonnage d’allocation

Par défaut, le type de profilage d’échantillonnage d’allocation signale uniquement les allocations qui sont encore actives à la fin de la session d’enregistrement. Les objets créés, supprimés, puis récupérés par la mémoire (GC) ne sont pas affichés dans l’outil Mémoire lors du profilage à l’aide de l’échantillonnage d’allocation ou de l’instrumentation d’allocation sur chronologie types.

Vous pouvez faire confiance au navigateur pour propre la mémoire de votre code. Toutefois, il est important de tenir compte du fait que gc lui-même est une opération coûteuse et que plusieurs CG peuvent ralentir l’expérience utilisateur de votre site web ou de votre application. Lors de l’enregistrement dans l’outil Performances avec la case Mémoire activée, vous pouvez voir l’opération GC se produire aux falaises abruptes (diminutions soudaines) dans le graphique de tas.

Opération GC affichée dans l’outil Performances

En réduisant la quantité de déchets que votre code crée, vous pouvez réduire le coût de chaque gc individuel et le nombre d’opérations gc. Pour suivre les objets ignorés par GC, configurez le type de profilage d’échantillonnage d’allocation avec les paramètres.

  1. Cliquez sur le bouton d’option Échantillonnage d’allocation .

  2. Cliquez sur les paramètres Inclure les objets ignorés par le gc principal et Inclure les objets ignorés par les paramètres GC mineurs .

    Paramètres GC de l’échantillonnage d’allocation

  3. Cliquez sur le bouton Démarrer .

  4. Sur la page web, effectuez les actions que vous souhaitez examiner.

  5. Cliquez sur le bouton Arrêter lorsque vous avez terminé toutes vos actions.

DevTools effectue désormais le suivi de tous les objets qui ont été gc’s lors de l’enregistrement. Utilisez ces paramètres pour comprendre la quantité de déchets générés par votre site web ou votre application. Les données signalées par l’échantillonnage d’allocation vous aideront à identifier les fonctions qui génèrent le plus de déchets.

Si vous examinez des objets qui n’ont été gc’s qu’au cours d’opérations gc majeures ou mineures spécifiques, configurez les paramètres de manière appropriée pour suivre l’opération qui vous intéresse. Pour en savoir plus sur les différences entre les gc majeurs et secondaires, consultez Trash talk : the Orinoco garbage collector | Blog du développeur du moteur JavaScript V8.

Repérer les garbage collection fréquentes

Si votre page semble s’interrompre fréquemment, vous pouvez rencontrer des problèmes de garbage collection.

Vous pouvez utiliser le Gestionnaire des tâches du navigateur Microsoft Edge ou les enregistrements de mémoire des performances pour repérer le garbage collection fréquent.

  • Dans le Gestionnaire des tâches du navigateur Microsoft Edge, les valeurs mémoire ou mémoire JavaScript qui augmentent et diminuent fréquemment représentent un garbage collection fréquent.

  • Dans les enregistrements de performances, les modifications fréquentes (en hausse et en baisse) apportées aux graphiques de nombre de segments de mémoire ou de nœuds JS indiquent un nettoyage de la mémoire fréquent.

Une fois que vous avez identifié le problème, vous pouvez utiliser une instrumentation d’allocation sur chronologie enregistrement pour savoir où la mémoire est allouée et quelles fonctions sont à l’origine des allocations.

Remarque

Certaines parties de cette page sont des modifications fondées sur le travail créé et partagé par Google et utilisées conformément aux conditions décrites dans la licence internationale 4,0 d’attribution créative. La page d’origine se trouve ici et est créée par Kayce Basques (Rédacteur technique, Chrome DevTools & Lighthouse).

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