Résoudre les problèmes de mémoire

Découvrez comment utiliser Chrome et les outils de développement pour détecter les problèmes de mémoire qui affectent les performances des pages, y compris les fuites de mémoire, la saturation de la mémoire et les récupérations fréquentes de mémoire.

Résumé

  • Utilisez le gestionnaire de tâches Chrome pour connaître la quantité de mémoire actuellement utilisée par votre page.
  • Visualisez l'utilisation de la mémoire au fil du temps avec les enregistrements de Vos trajets.
  • Identifiez les arborescences DOM dissociées (une cause fréquente de fuite de mémoire) avec les instantanés de tas 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.

Présentation

Dans l'esprit du modèle de performances RAIL, vos efforts doivent être axés sur vos utilisateurs.

Les problèmes de mémoire sont importants, car ils sont souvent perçus 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 peut s'agir d'un symptôme d'une 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 de mémoire par celle-ci au fil du temps.
  • Les performances d'une page sont systématiquement mauvaises. Il peut s'agir d'un symptôme de gonflement de la mémoire. On parle de surcharge de la mémoire lorsqu'une page utilise plus de mémoire que nécessaire pour obtenir une vitesse optimale.
  • Les performances d'une page sont retardées ou semblent être fréquemment mises en veille. Cela peut être dû à de fréquentes récupérations de mémoire. On parle de récupération de mémoire lorsque le navigateur récupère de la mémoire. Le navigateur décide quand cela se produit. Pendant les collections, toutes les exécutions de scripts sont suspendues. Ainsi, si le navigateur récupère beaucoup de mémoire, l'exécution du script est fortement interrompue.

Mémoire saturée: combien coûte "trop" ?

Une fuite de mémoire est facile à définir. Si un site utilise progressivement de plus en plus de mémoire, une fuite s'est produite. Toutefois, il est un peu plus difficile d'identifier les problèmes de mémoire gonflée. Qu'entend-on par "utiliser trop de mémoire" ?

Il n'y a pas de chiffres précis ici, car les capacités diffèrent selon les appareils et les navigateurs. La même page qui fonctionne correctement sur un smartphone haut de gamme peut planter sur un smartphone d'entrée de gamme.

L'essentiel ici est d'utiliser le modèle RAIL et de se concentrer sur vos utilisateurs. Identifiez les appareils populaires auprès de vos utilisateurs, puis testez votre page sur ces appareils. Si l'expérience est constamment mauvaise, 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 de tâches Chrome

Utilisez le gestionnaire de tâches Chrome comme point de départ pour rechercher les problèmes de mémoire. Le gestionnaire de tâches est un moniteur en temps réel qui vous indique la quantité de mémoire actuellement utilisée par une page.

  1. Appuyez sur Maj+Échap ou accédez au menu principal de Chrome et sélectionnez Plus d'outils > Gestionnaire de tâches pour ouvrir le gestionnaire de tâches.

    Ouverture du gestionnaire de tâches

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

    Activation de la mémoire JS

Ces deux colonnes vous indiquent des informations différentes sur l'utilisation de la mémoire par votre page:

  • La colonne Memory (Mémoire) représente la mémoire native. Les nœuds DOM sont stockés en mémoire native. 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 en temps réel 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 sont en augmentation.

Visualiser les fuites de mémoire avec les enregistrements de performances

Vous pouvez également utiliser le panneau "Performances" 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.

  1. Ouvrez le panneau Performances dans les outils de développement.
  2. Cochez la case Memory (Mémoire).
  3. Réalisez un enregistrement.

Pour illustrer les enregistrements de mémoire Performance, prenons l'exemple du code ci-dessous:

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 vous appuyez 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 transmise au tableau x. L'exécution de ce code produit un enregistrement de la chronologie, semblable à la capture d'écran suivante:

exemple de croissance simple

Tout d'abord, une explication de l'interface utilisateur. Le graphique HEAP du volet Overview (Aperçu) (en dessous de NET) représente le tas de mémoire JS. Sous le volet Aperçu se trouve le volet Compteur. Ici, vous pouvez voir l'utilisation de la mémoire répartie par tas de mémoire JS (comme le graphique HEAP dans le volet Vue d'ensemble), par documents, nœuds DOM, écouteurs et mémoire GPU. Le fait de décocher une case permet de la masquer dans le graphique.

Maintenant, analyse du code par rapport à la capture d'écran. Si vous examinez le compteur de nœuds (le graphique vert), vous pouvez constater qu'il correspond parfaitement au code. Le nombre de nœuds augmente par étapes discrètes. Vous pouvez supposer que chaque augmentation du nombre de nœuds est un appel à grow(). Le graphique de tas JS (le graphique bleu) n'est pas aussi simple. Conformément aux bonnes pratiques, la première baisse est en réalité une récupération forcée de mémoire (réussite en appuyant sur le bouton collect garbage). Au fur et à mesure de la progression de l'enregistrement, vous pouvez constater que la taille du tas de mémoire JS augmente. C'est normal et attendu: le code JavaScript crée les nœuds DOM à chaque clic sur le bouton et effectue une grande opération lorsqu'il génère la chaîne d'un million de caractères. L'aspect clé ici est le fait que le tas de mémoire JS se termine plus haut qu'il n'a commencé (le "début" correspond ici au point après la récupération forcée de la mémoire). Dans le monde réel, si vous constatiez une augmentation de la taille du tas de mémoire ou du nœud JS, cela peut potentiellement signifier une fuite de mémoire.

Détectez les fuites de mémoire de l'arborescence DOM dissociée avec les instantanés de tas de mémoire.

La récupération de mémoire d'un nœud DOM ne peut s'effectuer que s'il n'existe aucune référence à celui-ci dans l'arborescence DOM de la page ni dans le code JavaScript. Un nœud est considéré comme "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 dissociés sont une cause fréquente de fuite 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 dissocié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);

Cliquez sur le bouton référencé dans le code pour créer 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 dissociés.

Les instantanés de tas de mémoire sont un moyen d'identifier les nœuds dissociés. Comme leur nom l'indique, les instantanés de tas de mémoire montrent comment la mémoire est répartie entre les objets JavaScript et les nœuds DOM de votre page au moment de l'instantané.

Pour créer un instantané, ouvrez les outils de développement, accédez au panneau Memory (Mémoire), sélectionnez la case d'option Heap Snapshot (Instantané de tas de mémoire), puis appuyez sur le bouton Take Snapshot (Prendre un instantané).

prendre un instantané du segment de mémoire

Le traitement et le chargement de l'instantané peuvent prendre un certain temps. Une fois l'opération terminée, sélectionnez-la dans le panneau de gauche (nommée HEAP SNAPSHOTS).

Saisissez Detached dans la zone de texte Class filter (Filtre de classe) pour rechercher des arborescences DOM dissociées.

le filtrage des nœuds dissociés

Développez les carats pour examiner un arbre détaché.

enquêter sur un arbre détaché

Les nœuds surlignés en jaune ont une référence directe à eux dans le code JavaScript. Les nœuds surlignés en rouge n'ont pas de références directes. Ils ne sont vivants que parce qu'ils font partie de l'arbre du nœud jaune. En général, vous devez vous concentrer sur les nœuds jaunes. Corrigez votre code afin que le nœud jaune ne soit pas actif plus longtemps qu'il ne devrait l'être et vous vous débarrassez également des nœuds rouges qui font partie de l'arborescence du nœud jaune.

Cliquez sur un nœud jaune pour l'examiner plus en détail. Le volet Objets contient plus d'informations sur le code qui y fait référence. Par exemple, dans la capture d'écran ci-dessous, 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.

enquêter sur un nœud jaune

Identifier les fuites de mémoire du tas de mémoire JS à l'aide des délais d'allocation

La chronologie d'allocation est un autre outil qui peut vous aider à détecter les fuites de mémoire dans votre tas de mémoire JS.

Pour illustrer la chronologie d'allocation, considérez le code suivant:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

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

Pour enregistrer une chronologie d'allocation, ouvrez DevTools, accédez au panneau Profiles (Profils), sélectionnez la case d'option Record Allocation Timeline (Enregistrer la timeline d'allocation), appuyez sur le bouton Start (Démarrer), effectuez l'action que vous pensez être à l'origine de la fuite de mémoire, puis appuyez sur le bouton Stop Record (Arrêter l'enregistrement) (bouton d&#39;arrêt d&#39;enregistrement) lorsque vous avez terminé.

Pendant l'enregistrement, notez si des barres bleues s'affichent dans le calendrier d'allocation, comme dans la capture d'écran ci-dessous.

nouvelles allocations

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

chronologie d&#39;allocation avec zoom

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

détails de l&#39;objet

Examiner l'allocation de mémoire par fonction

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

Profileur d&#39;allocation d&#39;enregistrements

  1. Sélectionnez la case d'option Allocation Sampling (Échantillonnage d'allocation). Si un nœud de calcul se trouve sur la page, vous pouvez le sélectionner comme cible de profilage à l'aide du menu déroulant à côté du bouton Start (Démarrer).
  2. Appuyez sur le bouton Start (Démarrer).
  3. Effectuez les actions qui vous intéressent sur la page.
  4. Appuyez sur le bouton Arrêter lorsque vous avez terminé.

Les outils de développement présentent la répartition de l'allocation de mémoire par fonction. La vue par défaut est heavy (Bottom Up), qui affiche en haut les fonctions qui ont alloué le plus de mémoire.

Profil d&#39;allocation

Détecter les récupérations de mémoire fréquentes

Si votre page semble se mettre en pause fréquemment, vous rencontrez peut-être des problèmes de récupération de mémoire.

Vous pouvez utiliser les enregistrements de mémoire du gestionnaire de tâches Chrome ou de Vos trajets pour repérer les récupérations de mémoire fréquentes. Dans le gestionnaire des tâches, les valeurs de mémoire ou de mémoire JavaScript qui augmentent ou diminuent fréquemment représentent des récupérations de mémoire fréquentes. Dans les enregistrements de la chronologie, les graphiques de nombre de tas de mémoire ou de nœuds JS qui augmentent ou diminuent fréquemment indiquent des récupérations de mémoire fréquentes.

Une fois le problème identifié, vous pouvez utiliser un enregistrement de chronologie d'allocation pour savoir où la mémoire est allouée et quelles fonctions sont à l'origine de ces allocations.