Vue "Agrégats"

Il s'agit de la vue par défaut des captures de la heap (le tas en français). Cette vue ressemble à ceci :

À gauche, on retrouve l'heure à laquelle la capture a été prise ainsi que la taille totale de la heap de l'onglet.

À droite, on retrouve un tableau qui affiche une liste triée du contenu de la heap. Il y a quatre façons différentes de visualiser la heap. Pour passer de l'une à l'autre, il suffit d'utiliser la liste déroulante "Trier par" en haut du panneau :

Depuis Firefox 45, on retrouve en haut à droite le champ "Filtrer". Cela permet de filtrer le contenu affiché, afin par exemple de pouvoir rapidement voir combien d'objets d'une classe ont été alloués.

Coarse Type

Il s'agit du tri par défaut qui ressemble à ceci :

Cette option tire la heap par grandes catégories :

  • objects: Les objets JavaScript ou les objets des DOM/Web, tels que les objets Function et les noeuds DOM
  • other : Les objets internes du moteur JavaScript
  • scripts : les sources JavaScript chargées par la page.
  • strings: : (Chaines de caractères en français)

La colonne "Total Octets" affiche le nombre d'octets occupés par les objets de chaque catégorie, et le pourcentage de la taille totale de la heap que cela représente. Dans la capture d'écran ci-dessus, on peut voir que :

  • Les objects prennent 42% de la heap
  • Les other 27%
  • Les scripts 22%
  • Et les strings 9%

La colonne "Somme totale" affiche le nombre d'objets alloués actuellement de chaque catégorie. Il est a noter que le pourcentage affiché pour le nombre total n'est pas le bon, voir le bug 1222191.

Les noms des catégories ont une icône en forme de triangle. Celle-ci développe la catégorie afin d'avoir une catégorisation plus fine des éléments qui la composent. Par exemple, cliquer sur l'icône à côté de "objects" affichera les objets alloués, triés par classe :

Les noms des classes ici sont très communs, et cela révèle par exemple que 24% de la heap de l'onglet est occupé par des objets Function, et 1% par des objets Array.

Object Class

Ce tri permet d'afficher la mémoire utilisée par les objets JavaScript et les objets Web API, ordonnés par nom de classe :

Il est à noter que ce tri donne essentiellement les mêmes informations que le tri "Coarse Types" lorsque la catégorie "objects" est déroulée.

Il est également à noter que l'élément "other" est ici affiché en premier. Cet élément inclut tout ce qui n'est objet, et inclut les catégories other, scripts, et strings.

Internal Type

Ce tri affiche les mêmes données, mais du point de vue du moteur JavaScript SpiderMonkey. Ce tri sera plus probablement utile aux développeurs de Firefox (dont vous pouvez facilement faire partie ;) ) qu'aux développeurs web :



L'élément JSObject inclut tous les objets JavaScript et tous les objets WebAPI. La taille de cet élément sera donc la même que la taille de l'élément "objects" dans Le tri "Coarse Type", Et la même taille que tout le contenu dans Le tri "Object Class" à l'exception de "other".

Ce tri inclut également :

  • Les scripts (listés en tant que JSScript, js::LazyScript, et js::jit::JitCode)
  • Les strings (listés en tant que JSString)
  • Les objets internes ("other" dans le tri "Coarse Type") cela inclut js::Shape et d'autres "shapes" (les shapes sont utilisées dans SpiderMonkey pour une représentation efficace de plusieurs objets similaires).

Allocation Stack

L'Allocation Stack affiche exactement ou dans le code sont faites des allocations sur la heap.

Cette option étant gourmande en terme de performances, elle n'est pas activée par défaut. Pour l'activer, il faut :

  • Cocher la case "Enregistrer les piles d'allocations"
  • Recharger la page
  • Prendre une nouvelle capture
  • Sélectionner le tri "Allocation Stack"

Une liste de toutes les fonctions qui ont alloué des objets s'affichera alors. Cette liste est triée par la taille des allocations faites par chaque fonction :



La structure de ce tri ressemble fortement à celle de l'Arbre d'appel, à ceci près qu'il montre les allocations plutôt que des échantillons de processus. Ainsi, la troisième ligne par exemple concerne une fonction à la ligne 1 de "pubads_impl_75.js", cette ligne révèle que 313648 octets ont été alloués dans cette fonction ou dans des fonctions appelées par cette fonction. Il est possible d'utiliser l'icône en forme de triangle pour avoir plus de précisions et trouver l'endroit exact d'où l'allocation à été faite.

Il est plus simple d'expliquer ce comportement avec un exemple. Cette page contient contient simplement un script qui génère un grand nombre de nœuds DOM :

var toolbarButtonCount = 20;
var toolbarCount = 200;

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function createToolbarButton() {
  var toolbarButton = document.createElement("span");
  toolbarButton.classList.add("toolbarbutton");
  // stop Spidermonkey from sharing instances
  toolbarButton[getRandomInt(0,5000)] = "foo";
  return toolbarButton;
}

function createToolbar() {
  var toolbar = document.createElement("div");
  // stop Spidermonkey from sharing instances
  toolbar[getRandomInt(0,5000)] = "foo";
  for (var i = 0; i < toolbarButtonCount; i++) {
    var toolbarButton = createToolbarButton();
    toolbar.appendChild(toolbarButton);
  }
  return toolbar;
}

function createToolbars() {
  var container = document.getElementById("container");
  for (var i = 0; i < toolbarCount; i++) {
    var toolbar = createToolbar();
    container.appendChild(toolbar);
  }
}

createToolbars();

Voici une représentation en pseudo-code et ce que fait ce programme :

createToolbars()
    -> createToolbar() // called 200 times, creates 1 DIV element each time
       -> createToolbarButton() // called 20 times per toolbar, creates 1 SPAN element each time

Réalisons maintenant une allocation trace. Pour cela, il faut :

  1. Ouvrir l'outil Mémoire
  2. Cocher "Enregistrer les piles d'allocations"
  3. Charger la page https://mdn.github.io/performance-scenarios/dom-allocs/alloc.html
  4. Prendre une capture
  5. Choisir le tri Allocation Stack

Quelque chose comme ceci devrait apparaitre :

Cela révèle que la taille totale de la stack est de 5.00 MB, dont 89% sont allouées par des fonctions appelées depuis "alloc.js", à la ligne 35 (le premier appel à createToolbars()).

Afin de savoir exactement d'où est allouée la mémoire, il est possible de développer la ligne :

C'est dans ce cas que les colonnes "Octets" et "Somme" sont utiles. Elles révèlent en effet la taille et le nombre des allocations faites à ce point précis. Ainsi dans l'exemple ci-dessus, ile est possible de voir que :

  • Dans createToolbarButton(), à la ligne 9 de alloc.js, 4002 allocations ont été faites et que cela représente 84% de la heap totale. Il s'agit de l'endroit exact ou les éléments <span> sont crées.
  • 200 allocations (5% de la heap totale), ont été faites dans createToolbar() à la ligne 17 de alloc.js. Il s'agit de l'endroit exact ou les éléments <div> sont crées.

Inverser l'arbre d'appels

La vue par défaut est une vue "top-down" : elle affiche les allocations qui arrivent à un point ou en des points plus loin dans l'arbre. C'est pratique pour avoir une vue d'ensemble des endroits ou le programme consomme beaucoup de mémoire. Cependant cette vue implique de devoir parcourir un long chemin pour trouver l'emplacement exact d'où les allocations sont faites.

L'option "Inverser l'arbre" aide à résoudre ce problème. Cela donne en effet une vue "bottom-up" du programme, affichant les endroits exacts d'où les allocations proviennent, ordonnés par taille d'allocation. L'icône en forme de triangle fait alors un retour au premier niveau de l'arbre.

Voici à quoi ressemble l'arbre après avoir coché l'option "Inverser l'arbre" :

Maintenant, la première ligne affiche directement l'appel createToolbarButton() qui correspond à l'allocation de 84% de la heap de la page. On retrouve en troisième position l'appel createToolbar() qui correspond lui à 5% de la heap.

(no stack available)

Dans l'exemple ci-dessus, il y a une ligne nommée "(no stack available)" qui correspond à 10% de la heap.  La présence de cette ligne s'explique par le fait que toute l'utilisation de la heap n'est pas due au script JavaScript.

Exemples d'usage de la heap non alloué par un script :

  • Tous les scripts que la page charge occupent de l'espace dans la heap
  • Quelques fois, un objet est alloué lorsqu'il n'y a pas de JavaScript sur la stack. Par exemple, les objets DOM Event sont alloué avant que le JavaScript ne soit exécuté et avant que les évènements ne soient appelés.

Bon nombre de pages web auront une part de "(no stack available)" bien supérieure à 10%.

Étiquettes et contributeurs liés au document

 Contributeurs à cette page : maximelore, solfen
 Dernière mise à jour par : maximelore,