La vue Allocations de l'outil Performance affiche quelles fonctions dans une page web allouent le plus de mémoire durant le profil.
C'est important pour la performance, car allouer beaucoup de mémoire ou faire beaucoup d'allocations peut activer le ramasse-miette (garabage collector). Celui-ci peut affecter la réactivité de la page.
La vue Allocations est une des nouveautés de Firefox 46.
Pour activer la vue Allocations, il faut activer l'option "Enregistrer les Allocations" dans les options de l'outil Performance, avant d'enregister un profil. Il faut ensuite enregistrer un profil, un nouvel onglet nommé "Allocations" apparaitra alors dans la barre d'outils :
Anatomie de la vue allocations
La vue allocations ressemble à ceci :
Cette vue fait périodiquement des échantillons des allocations qui sont faites durant l'enregistrement. Chaque ligne représente une fonction pour laquelle au moins un échantillon d'allocation a été pris durant l'enregistrement.
La vue inclut les colonnes suivantes :
- Self Count: Le nombre d'échantillons d'allocations qui ont été prises dans cette fonction (affiché également en pourcentage du total)
- Self Bytes: Le nombre total d'octets qui ont été alloués dans les échantillons d'allocations dans cette fonction (affiché également en pourcentage du total)
Les lignes sont triées par la colonne "Self Bytes".
Anisi dans l'exemple ci-dessus :
- 8904 échantillons ont été pris dans la fonction
signalLater()
, ce qui représente 28.57% du nombre total d'échantillons pris. - Ces échantillons ont alloué 1102888 octets, ce qui représente 30.01% de la taille totale de mémoire alloué par tous les échantillons.
À côté de chaque nom de fonction, se trouve une flèche de développement. Cliquer sur celle-ci affichera l'endroit d'où la fonction a été appelée :
Ici, il est possible de voir que signalLater()
a été appelée depuis deux endroits : removeInner()
et setSelectionInner()
. Il est ainsi possible de remonter l'arbre d'appel et de mieux comprendre le contexte de ces allocations.
Self Cost et Total Cost
Les colonnes de coût sont séparées en "Self" et en "Total". La colonne "Self" correspond aux échantillons pris seulement dans cette fonction. La colonne "Total" correspond aux échantillons pris dans cette fonction ou dans les fonctions appelées par cette fonction. Au premier niveau, ces deux colones sont les mêmes, vu que la vue représente les dernières fonctions (il s'agit d'une vue inversée de l'arbre d'appel). Mais, si l'on remonte l'arbre en développant les lignes, alors la différence devient visible.
Ici, 8904 échantillons ont été pris dans signalLater()
. Mais signalLater()
a été appelé depuis deux endroits : removeInner()
et setSelectionInner()
. Mais ces deux fonctions ont 0 en Self Count, ce qui veut dire qu'aucune allocation n'a été faite depuis ces fonctions. Cependant removeInner()
a 8901 en Total Count, tandis que setSelectionInner()
a seulement 3 en Total Count. Cela révèle que sur les 8904 allocations faites dans signalLater()
, toutes sauf trois proviennent de la branche removeInner()
.
Allocations et garbage collection
Bien sûr, en savoir plus sur l'utilisation mémoire d'un site est très utile. Cependant la connexion principale entre la réactivité d'un site et le profil d'allocation réside dans le coût de la garbage collection (GC) (ramasse-miette).
Dans un langage à ramasse miette comme JavaScript, le runtime a périodiquement besoin de parcourir la heap à la recherche d'objets qui ne sont plus accessibles, pour libérer l'espace mémoire qu'ils occupent. Lors du passage du ramasse-miette, le moteur JavaScript doit être mis en pause, le programme est donc suspendu et ne répondra pas.
Pour réduire l'impact de ce phénomène sur la réactivité des sites, SpiderMonkey (le moteur JavaScript de Firefox) possède un ramasse-miette incrémental. Celui-ci procède par petites étapes, lassant le programme tourner entre chaque incrémentation. Quelques fois cependant le moteur a besoin de réaliser un passage complet non incrémental et le programme doit alors attendre la fin du nettoyage.
Les passages du ramasse-miette sont affichés en rouge dans la vue Chronologie, et sont des véritables points noirs pour la réactivité, ils peuvent en effet prendre jusqu'a des centaines de millisecondes :
Que faire en cas de passage intempestif du ramasse-miette ? SpiderMonkey utilise un ensemble complexe d'heuristiques pour déterminer quand et quel type de passage de ramasse-miette est nécessaire.
En général, cependant : "l'allocation pressure" - allouer beaucoup de mémoire ou allouer de la mémoire a haute fréquence - tend a augmenter la probabilité de SpiderMonkey à ordonner le passage du ramasse-miette, et tend également a faire plus de passages non incrémentaux.
Si un passage du ramasse-miette a été causé par de "l'allocation pressure", alors le panneau droit du marqueur dans la vue Chronologie contient un lien nommé "Show allocation triggers". Cliquer sur celui-ci passe la vue en vue allocations et sélectionne la période de temps entre la fin du dernier passage du ramasse-miette et le début de celui qui a été cliqué. Cela révèle toute les allocations qui ont amené à déclencher ce passage du ramasse-miette :
Si vous rencontrez ces problèmes, il est conseillé d'essayer de réduire la taille de vos allocations. Par exemple :
- Est-il possible d'allouer de la mémoire en "lazy load", lorsqu'elle est nécessaire plutôt que de l'allouer en avance ?
- Si vous allouez de la mémoire dans une boucle, pouvez-vous réutiliser une seule allocation dans chaque itération ?