• Aucun résultat trouvé

Outils de profiling sur la durée de vie des objets

Dans le document Profilage mémoire d’applications OCaml (Page 76-79)

Certains outils de profiling se focalisent sur la durée de vie des objets en mémoire. En faisant cette hypothèse, ces outils tentent de trouver les objets en mémoire les moins utilisés ou de détecter ceux qui ne le sont plus depuis une certaine durée.

4.3.1 Sleigh, détecter les fuites mémoire

Sleigh [20] est un outil de profiling tentant de détecter des fuites mémoire, en se basant sur la date de dernière utilisation d’un objet (staleness en anglais). Si un objet est inutilisé pendant une longue durée, il sera signalé lors du rapport émis.

De plus, les objets en mémoire sont encodés d’une façon astucieuse de manière à n’utiliser qu’un bit dans l’en-tête pour stocker l’information sur le site d’allocation, ainsi que son site de dernière utilisation. Une fois les objets suspicieux en mémoire détectés, il est alors plus aisé de retrouver dans le code source l’endroit exact où ils ont été alloués et l’endroit exact où les objets ont été utilisés. Bond et al. détaillent dans [20] cette approche statistique pour encoder les sites d’allocation dans l’en-tête des objets.

Sleigh utilise des emplacements non-utilisés dans l’en-tête de chaque bloc mémoire,

il n’y a donc aucun surcoût au niveau de l’espace utilisé. Cependant, il y a un surcoût de 29% à l’exécution dû à l’instrumentation ajoutée par l’outil.

Le code est instrumenté pour chaque allocation, et les en-têtes sont lus pour identifier les objets non utilisés depuis un certain temps. 4 bits seront introduits dans le header de sorte à ajouter :

• 1 bit pour le site d’allocation.

• 1 bit pour le site de dernière utilisation • 2 bits pour le temps de dernière utilisation.

Sleigh commence par ajouter dans cet espace le site d’allocation ainsi que le champ

de dernière utilisation. Si un objet n’est jamais utilisé, alors ces deux champs auront toujours la même valeur.

Les 2 bits pour le temps de dernière utilisation sont mis à 0 à chaque nouvelle allocation (initialisation de l’objet) et à chaque fois que l’objet est utilisé. Ces 2 bits sont incrémentés de k à k + 1 si le GC courant est divisible par bk, où b représente la base

du compteur logarithmique (la valeur 4 est utilisé par défaut). Ce compteur utilise une échelle logarithmique, ce qui permet de sauver de l’espace mémoire sans perdre beaucoup d’informations. La saturation pour ce compteur est atteinte à 3, à cause du codage sur deux bits.

Conclusion

Le surcoût en temps d’exécution de 29% en moyenne est un inconvénient non négli- geable sur des applications tournant en production.

De plus, Sleigh ne supporte par le déplacement d’objets. Il fonctionne avec un ramasse- miettes à balayage sans déplacements d’objets.

Il peut également y avoir quelques imprécisions sur les objets reportés. Le fait de n’utiliser que le temps de dernière utilisation fait que les objets plus gros en mémoire peuvent passer inaperçus entre tous les objets reportés.

Dans le monde Java, il peut y avoir quelques faux-positifs notamment lors de l’utili- sation de frames dans Java Swing, qui sont alloués une fois en début de programme et peuvent ne pas être utilisés pendant une durée très longue.

Enfin, l’outil utilise l’information de classe à runtime de Java et n’est donc pas facilement applicable à d’autres langages.

4.3.2 Profiler les conteneurs

On a également des approches avec un niveau d’abstraction basé sur les conte- neurs [97] et ses opérations. Les auteurs introduisent deux concepts qui vont permettre de décider de l’importance des fuites d’un conteneur :

• quantité de la mémoire utilisée • la caducité (staleness)

L’idée de cette nouvelle approche est de tracer seulement les conteneurs responsables de la plupart des fuites mémoire en Java, au lieu de tracer tous les objets. Tous les conteneurs sont alors suspectés de fuites mémoires. Cette approche peut être complétée par des techniques de suppression automatique de fuites liées aux tableaux [76].

L’idée de base est concentrée sur le fait qu’un conteneur a trois opérations courantes : l’ajout, la suppression et la lecture d’un élément de ce conteneur. À la fin de l’exécution d’un programme, pour une structure donnée, si le nombre d’ajouts est équivalent au nombre de suppressions, alors celle-ci n’est pas considérée comme fuyante.

Cette idée est complétée par un calcul sur la fiabilité et l’importance de la fuite mémoire, basée sur la quantité consommée (MC) et la caducité (SC).

Le MC est la quantité de mémoire que le conteneur consomme durant sa vie. La valeur relative à un temps τ du MC (qui est dans l’intervalle [0, 1]), est le ratio entre la somme de toute la mémoire consommée par tous les objets atteignables par le contenur et le total de mémoire consommé par le programme à τ .

Le SC est la distance entre le moment où un élément est enlevé du conteneur et le moment le plus récent où cet élément est récupéré/ajouté de/à celui-ci.

Les auteurs définissent alors un indice de fiabilité sur la fuite (LC : Leaking Confidence) : LC = SC × MC1−SC où LC ∈ [0, 1]

On peut alors déduire les propriétés suivantes :

• pour MC=0 et SC ∈ [0, 1] alors LC = 0 : si le MC d’un conteneur est assez

petit, son LC sera proche de 0 (la caducité ici n’importe pas). Cette propriété permet de filtrer les petits objets comme les chaînes de caractère (String) ;

• pour SC=0 et MC ∈ [0, 1] alors LC = 0 : si chaque élément d’un conteneur est

retiré dès lors qu’il n’a plus d’utilité, son LC est de 0 quelque soit sa taille ;

• pour SC=1 et MC ∈ [0, 1] alors LC = 1 : si aucun élément d’un conteneur n’est

jamais retiré, son LC est de 1 quelque soit la taille du conteneur ;

• MC=1 et SC ∈ [0, 1] alors LC = SC : si le MC d’un conteneur est très élevé,

Conclusion

Pour utiliser cet outil, il est nécessaire d’instrumenter manuellement le code des conteneurs. En effet, une fois passée cette étape, l’outil fera une analyse hors ligne (post- mortem), après que le programme se soit arrêté normalement ou pas.

Un inconvénient de cette approche est qu’elle ne capture qu’une partie des fuites mémoires : celles basées sur les conteneurs. Pour finir, une recherche plus approfondie est nécessaire sur les conteneurs non mutables, ainsi que sur les tableaux de pointeurs faibles (weak arrays).

Dans le cas d’OCaml, il serait possible de faire la même chose pour certaines struc- tures mutablesIl faudrait pour cela complètement annoter la librairie standard et fournir des nouveaux modules pour ce genre de valeurs.

Dans le document Profilage mémoire d’applications OCaml (Page 76-79)