Rererere-bonjour!
On sent que le code freeze pour Firefox 6 est dans moins de 48 h car tout ce qui était prêt arrive sur Nightly.
Là, c'est un bug mineur corrigé, un quasi-leak, mais vu les soucis de gestion de mémoire, il est intéressant à analyser et à bloguer à son sujet!
Une consommation excessive de mémoire peut être due à plusieurs causes:
- une cause algorithmique, c'est-à-dire un choix du développeur qui décide d'utiliser plus de mémoire pour gagner de la vitesse;
- de la fragmentation mémoire. Le programme se comporte bien, mais l'allocateur mémoire s'emmêle les pinceaux et n'est plus capable de réallouer certaines parties de mémoire. L'utilisation d'arenas et d'allocateurs mémoire plus performants, comme jemalloc permet de corriger ce genre de problèmes;
- des leaks ou fuites. Le développeur réserve de la mémoire mais ne la rend jamais; c'est assez courant en C/C++ si on ne fait pas attention;
- des quasi-leaks qui donnent le même symptôme, mais qui ont une cause radicalement différente. Là, la mémoire est bien rendue mais trop tard. Il y a deux grands groupes:
- les quasi-leaks causés par les utilisateurs; cela arrive souvent avec les systèmes à ramasse-miettes; le dév pense ne plus détenir de référence(s) sur la donnée inutile, mais oublie une référence, par exemple dans un historique. L'objet n'est ainsi jamais relâché, mais le dev ne le sait pas. De plus tous les objets liés par celui-ci ne sont jamais collectés par le ramasse-miette. Cela est la principale cause de consommation indue de mémoire par certaines extensions.
- les quasi-leaks systémiques; là le développeur d'extension ou de code est blanc comme neige. C'est le système (le ramasse-miette) qui est la cause du problème. Pour différentes raisons il laisse des miettes!
Parmi les leaks/quasi-leaks corrigés presque quotidiennement ces jours-ci, il y en a un qui sort du lot:
Bug 654399 — Page has memory grow for a good long while before a GC ever happens
C'est un magnifique exemple de
quasi-leak systémique. Voici ce qu'il se passe. Le symptôme, c'est une croissance anormale de la mémoire de 1200 bytes/5 ms soit 240 kB/s ou 12 MB/min lorsqu'on charge une page précise. La mémoire augmente donc rapidement de plus de 300 MB! Puis au prochain passage du ramasse-miette, tout redevient normal.
Le hic, c'est pourquoi le ramasse-miette ne passe plus tôt. En effet, le ramasse-miette est lancé périodiquement, et pour éviter de tout arrêter pour faire le rangement (ce qu'on appelle
stop-the-world), il utilise un algorithme beaucoup plus simple, pour estimer si cela vaut la peine de faire le ménage maintenant (y a-t-il assez de déchets). Cet algorithme est imparfait et sous-estime parfois la mémoire occupée indûment. À priori ce n'est pas très grave, car cela repousse juste son déclenchement, et la mémoire est quand même libérée, un peu plus tard.
Sauf que dans certains cas, comme la page web en question, il est produit beaucoup plus de déchets mémoire indétectables, quede détectables. Bilan, si on ne regarde que cette page, et que l'on ne fait pas d'autres activités générant des déchets mémoire, la mémoire n'est pas libérée (ou très très raremeent) et comme elle grandit beaucoup (genre 1/2 GB!), cela pause problème.
Les devs ont donc amélioré l'algorithme d'évaluation de la saleté, tout en sachant que cela ne couvre pas tous les cas. Seul un nouveau ramasse-miette moderne, basé sur la technologie
Generational Garbage Collection, permettra de résoudre ce problème (et d'autres) dans tous les cas. Un tel ramasse-miette est prévu, mais cela prend du temps (c'est un composant critique) et devrait arriver d'ici la fin de l'année (la première étape, un ramasse-miette incrémental est en cours d'implémentation).
Voilà!
La liberté n'est jamais accordée de bon gré par l'oppresseur; elle doit être exigée par l'opprimé (Martin Luther King).
Les convictions sont des ennemis de la vérité plus dangereux que les mensonges. (Nietzsche).
Native Mozillian.