Résoudre les problèmes de mémoire

Kayce basque
Kayce basque

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, les surcharges de mémoire et les récupérations de mémoire fréquentes.

Résumé

  • Le gestionnaire de tâches Chrome vous permet de connaître la quantité de mémoire actuellement utilisée par votre page.
  • Visualisez l'utilisation de la mémoire au fil du temps grâce aux enregistrements de vos trajets.
  • Identifiez les arborescences DOM dissociées (cause fréquente de fuites de mémoire) avec les instantanés de tas de mémoire.
  • Sachez 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 en termes de performances doivent être axés sur les 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. Cela peut être le 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 croissante de mémoire au fil du temps.
  • Les performances d'une page sont systématiquement mauvaises. Cela peut être symptomatique d'une saturation de la mémoire. On parle de surcharge de mémoire lorsqu'une page utilise plus de mémoire que nécessaire pour une vitesse optimale.
  • Les performances d'une page sont retardées ou semblent se mettre en veille fréquemment. Cela peut être symptomatique de fréquentes récupérations de mémoire. La récupération de mémoire a lieu lorsque le navigateur récupère de la mémoire. Le navigateur décide de le faire. Pendant la collecte, toute exécution des scripts est suspendue. Par conséquent, si le navigateur récupère beaucoup de mémoire, l'exécution du script sera souvent mise en pause.

Mémoire gonflée: combien signifie "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 la saturation de la mémoire est un peu plus difficile à cerner. Qu'entend-on par "utilisation excessive de mémoire" ?

Il n'y a pas de chiffres précis dans le cas présent, car les capacités diffèrent selon les appareils et les navigateurs. La même page qui s'affiche correctement sur un smartphone haut de gamme peut planter sur un smartphone bas de gamme.

La clé ici est d'utiliser le modèle RAIL et de se concentrer sur vos utilisateurs. Identifiez les appareils les plus populaires auprès de vos utilisateurs, puis testez votre page sur ces appareils. Si l'expérience est systématiquement médiocre, il est possible que la page dépasse les capacités de mémoire de ces appareils.

Surveillez l'utilisation de la mémoire en temps réel avec le gestionnaire de tâches Chrome

Utilisez le gestionnaire de tâches de Chrome comme point de départ pour identifier un problème 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. Dans le gestionnaire de tâches, effectuez un clic droit sur l'en-tête du tableau, puis activez Mémoire JavaScript.

    Activer la mémoire JS

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

  • 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 temps réel (le nombre entre parenthèses). Il représente la quantité de mémoire utilisée par les objets accessibles sur votre page. Si ce nombre augmente, cela signifie que des objets sont créés ou que les objets existants augmentent.

Visualiser les fuites de mémoire grâce aux enregistrements de performances

Vous pouvez également utiliser le panneau "Performances" comme autre point de départ pour 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. Créez un enregistrement.

Pour illustrer les enregistrements de mémoire de Performance, utilisez le 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 génère un enregistrement de la chronologie, semblable à la capture d'écran suivante:

exemple de croissance simple

Tout d'abord, voici une explication de l'interface utilisateur. Le graphique HEAP du volet Overview (Aperçu) (sous NET) représente le tas de mémoire JS. Sous le volet Overview (Aperçu), se trouve le volet Counter (Compteur). Vous pouvez voir ici l'utilisation de la mémoire répartie par tas de mémoire JS (identique au graphique HEAP du volet Overview) et par documents, nœuds DOM, écouteurs et mémoire GPU. Si vous décochez une case, la case correspondante n'apparaît plus dans le graphique.

Examinons maintenant une analyse du code par rapport à la capture d'écran. Si vous examinez le compteur de nœuds (graphique vert), vous pouvez constater qu'il correspond parfaitement au code. Le nombre de nœuds augmente par étapes discrètes. Vous pouvez partir du principe que chaque augmentation du nombre de nœuds correspond à un appel à grow(). Le graphique du tas de mémoire JS (le graphique bleu) n'est pas aussi simple. Conformément aux bonnes pratiques, la première baisse correspond en réalité à une récupération de mémoire forcée (obtenue en appuyant sur le bouton collecter la mémoire). À mesure que l'enregistrement progresse, vous pouvez constater que la taille du tas de mémoire JS augmente. C'est naturel et attendu: le code JavaScript crée les nœuds DOM à chaque clic sur le bouton. La chaîne d'un million de caractères génère beaucoup de travail. L'élément clé ici est le fait que le tas de mémoire JS se termine plus haut qu'il n'a commencé (le "début" étant ici le point après la récupération de mémoire forcée). En situation réelle, si vous observez ce modèle d'augmentation de la taille du tas de mémoire ou des nœuds JS, il peut s'agir d'une fuite de mémoire.

Découvrir les fuites de mémoire de l'arborescence DOM dissociée avec les instantanés de segment de mémoire

Un nœud DOM ne peut être récupéré que s'il n'y a aucune référence à celui-ci dans l'arborescence DOM ou le code JavaScript de la page. Un nœud est considéré comme "détaché" 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 identifier les nœuds dissociés à l'aide des profileurs de segments de mémoire des outils de développement.

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);

Un clic sur le bouton référencé dans le code crée 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 permettent d'identifier les nœuds dissociés. Comme leur nom l'indique, les instantanés de tas 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, accédez au panneau Memory (Mémoire), sélectionnez la case d'option Heap Snapshot, puis appuyez sur le bouton Take Snapshot (Prendre un instantané).

prendre un instantané de 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é HEAP SNAPSHOTS).

Saisissez Detached dans la zone de texte Filtre de classe pour rechercher les 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 font directement référence au 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'arborescence 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 reste pas actif plus longtemps que nécessaire et supprimez également les nœuds rouges qui font partie de l'arborescence du nœud jaune.

Cliquez sur un nœud jaune pour examiner le problème plus en détail. Dans le volet Objets, vous pouvez consulter 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.

d&#39;examiner un nœud jaune

Identifier les fuites de mémoire du tas de mémoire JS grâce aux timelines 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 le calendrier d'allocation, tenez compte du 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 enfoncé, 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 Profiles (Profils), sélectionnez la case d'option Record Allocation Timeline (Enregistrer la chronologie d'allocation), appuyez sur le bouton Start (Démarrer), effectuez l'action qui, selon vous, est à l'origine de la fuite de mémoire, puis appuyez sur le bouton Stop recording (Arrêter l'enregistrement) (bouton d&#39;arrêt de l&#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 vos candidats aux fuites de mémoire. Vous pouvez zoomer sur une barre pour filtrer le volet Constructeur et n'afficher que les objets alloués pendant 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 à son sujet dans le volet Objet. Par exemple, dans la capture d'écran ci-dessous, en affichant les détails de l'objet nouvellement alloué, vous pouvez voir qu'il a été alloué à la variable x dans le champ d'application Window.

détails de l&#39;objet

Analyser l'allocation de mémoire par fonction

Utilisez le type Allocation Sampling (Échantillonnage de l'allocation) dans le panneau Memory (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 sur la page que vous souhaitez examiner.
  4. Appuyez sur le bouton Stop lorsque vous avez terminé.

Les outils de développement affichent la répartition de l'allocation de mémoire par fonction. La vue par défaut est Heavy (Bottom Up). Il s'agit des fonctions qui ont alloué le plus de mémoire en haut de la page.

Profil d&#39;allocation

Identifier les récupérations de mémoire fréquentes

Si votre page semble se mettre souvent en pause, 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 Timeline pour identifier les récupérations de mémoire fréquentes. Dans le gestionnaire des tâches, les valeurs Memory (Mémoire) ou JavaScript Memory (Mémoire JavaScript) dont la hausse ou la baisse sont fréquentes représentent des récupérations de mémoire fréquentes. Dans les enregistrements de timeline, les graphiques de tas de mémoire ou de nombre de nœuds JS fréquemment croissants et en baisse indiquent des récupérations de mémoire fréquentes.

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