Vous êtes sur la page 1sur 14

21- 1 02 03 2

U IE ST H SA 1 RS T A N V R I A S N E E T T E OL N TON L D S CE C S P LQU E C E A I A E E S IN E A P I S K OU IG H RB A

2 M A N EC C EI G N E R N Y L N IU G N EE E T I E I L C RQU

E AR MB QU TP R M /O YE A R M E I ONE NT NV R ME
G SIND L M I D N U ET O E A MOR A S N E

Y CN A A A S U A IE . MK SO

E I ONE NTE ARAM /OM NV R ME MB TP QU YE R R


G SI D L M R D N U E VR E N E A QU ET ON E A MOIE A S N N ION ME T MB R (Y ER M R T P A OM)
R A IE P R E LS R A

G SIND L M I D N U ET O E A MOR A S N E

E C D EP R N A R A

Y CN A D S L M A IE B SA A A AS MK SOU

D . .H I R K R OF R

2 1 -0 3 0 22 1

Pour stocker les donnes ncessaires son excution, un programme informatique utilise des , qui correspondent autant demplacements dans la mmoire physique du systme. Les diffrents langages de programmation offrent au programmeur diverses abstractions permettant daccder cette mmoire, ainsi que des oprations primitives permettant dy rserver de lespace ou den librer. Un composant logiciel appel se charge alors des tches de comptabilit associes, comme linventaire des zones libres et occupes. Lutilisation de mmoire dynamique offre un confort de programmation considrable au dveloppeur, mais soulve des questions dimplantation parfois difficiles, en particulier dans un contexte embarqu et temps-rel. Dans ce chapitre, on explore les diffrentes approches du problme de la gestion mmoire, et leurs avantages et inconvnients respectifs, en particulier vis--vis de la prvisibilit en temps des oprations associes.

Aspects lis au matriel

La mmoire est un lment essentiel de tout systme informatique. Lunit arithmtique et logique (UAL), au cur du processeur, ne serait en effet daucune utilit si elle ne disposait pas dun moyen pour mmoriser les rsultats de ses calculs, afin de les rutiliser plus tard au cours de lexcution du programme. Au plus proche de lUAL se trouvent les registres internes du processeur, que lon peut dj considrer comme une certaine sorte de mmoire. Leur nombre est trs limit, mais leur temps daccs tant optimal, ils sont essentiels la performance du processeur. En complment, on utilise donc dautres types de mmoire, de tailles de plus en plus importantes, au prix de temps daccs de plus en plus longs. Cette dpend bien sr du systme considr, mais comporte en gnral les niveaux suivants : les sont situs au cur du processeur. La ou est destine masquer les temps daccs la , situe lextrieur au processeur. La , ou , est persistante, cest dire que les donnes quelle contient ne sont pas perdues en cas darrt du systme, mme si elle na pas vocation les conserver trs long terme, contrairement la . Sur un ordinateur de bureau typique, la mmoire cache sera partie intgrante du processeur. Pour des raisons de performances, on trouvera mme typiquement deux niveaux successifs de mmoire cache, appels L1 et L2 ( et ). La mmoire centrale sera constitue des barrettes de mmoire vive installe sur la carte mre. Cest le disque dur de lordinateur qui sert de mmoire de masse, et larchivage est en gnral effectu manuellement sur des supports externes, par exemple via des bandes magntiques, ou un graveur de disques. Cette hirarchie nest pas tout le temps respecte. En effet, grce la prsence dans le matriel dune (MMU), un systme dexploitation classique exploitera typiquement plusieurs types de mmoire diffrents de faon transparente pour le programme, grce des mcanismes

de mmoire virtuelle et de pagination. La est une technique permettant de dissocier les manipules par le programme des o sont stockes rellement les donnes. Lunit de gestion mmoire (MMU) est un composant matriel charg de traduire les adresses virtuelles en adresses physiques. Elle est en gnral utilise conjointement avec des mcanismes de , cest dire que lensemble de la mmoire est divis en de taille fixe. Une table de correspondance est utilise pour mmoriser quelle page de la mmoire physique contient chaque page de la mmoire virtuelle. Ces deux mcanismes permettent au systme dinstaurer un ( ) des pages entre diffrents emplacements physiques, et de relguer par exemple sur le disque dur les pages les moins utilises. Dun autre ct, sur un systme embarqu aux ressources limites, on naura typiquement pas besoin darchivage, et il ny aura souvent pas de mmoire cache. En effet, la prsence de mmoire cache rend les performances temporelles plus difficiles prvoir, ce qui nest pas souhaitable si le systme est soumis des contraintes temps-rel (cf section 2.5). La mmoire vive sera assez rduite, du fait de son cot important par rapport la mmoire de mmoire de masse : par exemple, un baladeur mp3 ne disposera typiquement1 que de quelques mga-octets de RAM pour plusieurs giga-octets de mmoire flash. De plus, les systmes dexploitation pour systmes embarqus sont plus simples, souvent sans mmoire virtuelle, et doivent donc grer avec soin les ressources mmoire.

Dans le cadre des systmes embarqus et temps-rel, lallocation sur le tas nest utilise quavec parcimonie car il est souvent difficile den prvoir le comportement. Dans le reste de ce chapitre, nous allons voir un aperu de diffrentes approches qui sattaquent au problme de la gestion de la mmoire dynamique, ainsi que leurs affinits avec lembarqu et le temps-rel.

2.

Gestion manuelle de la mmoire dynamique

Dans la plupart des langages impratifs, la mmoire dynamique est manipule explicitement par le programme. Lapproche traditionnelle consiste offrir au programmeur des oprations primitives pour lallocation et la dsallocation, comme par exemple les fonctions malloc() et free() du langage C. Chaque fois que le programmeur a besoin dun nouveau bloc mmoire de taille n, il appelle malloc(n) qui lui rend un pointeur p sur le bloc nouvellement allou, et lorsquil nen a plus besoin, il passe le pointeur p la fonction free().

Pointeurs invalides

Cette apparente simplicit de programmation cache en ralit des difficults considrables, la principale tant de sassurer que le programme naccde jamais des blocs non allous, ou prcdemment dsallous. On parle de pointeurs invalides, ou , pour dsigner des rfrences des zones mmoires o le programme na pas le droit daccder. Dans le cadre dun systme dexploitation classique, laccs invalide est en gnral intercept par le systme qui interrompt brutalement le programme. Les programmeurs C contournent souvent ce problme en ne dsallouant pas du tout la mmoire, qui sera implicitement libre en bloc la terminaison du programme. Cette ide nest pas cependant pas applicable lorsque le programme est destin sexcuter pendant une trs longue priode, comme cest typiquement le cas pour un systme embarqu. Cette grande difficult de dterminer et dsallouer la mmoire est une des faiblesses principales de tous les langages qui utilisent cette technique. En effet, les erreurs dexcution associes sont trs difficiles reproduire, ce qui complique beaucoup le travail de correction des programmes.

Fuites de mmoire Un autre inconvnient considrable de la gestion manuelle de la mmoire est


la ncessit de sassurer que les blocs devenus inutiles sont bien librs au fur et mesure. Si ce nest pas le cas, ils saccumulent et finissent par occuper tout lespace disponible. Le systme ne trouve alors plus de place o allouer de nouveaux blocs et rencontre une faute dexcution. On appelle ce phnomne (ou ). Dun certain ct, on peut distinguer deux sortes de causes qui provoquent des fuites de mmoire : les fuites , et les fuites . Les premires sont dues un nombre toujours croissant dobjets vivants, souvent cause dune du programme. Par exemple, une liste chane laquelle on ne ferait que rajouter des lments, sans jamais les dsallouer, finira tt ou tard par occuper toute la mmoire. Le programme nest pas vraiment incorrect fonctionnellement parlant, car il sexcuterait correctement si lon disposait dune quantit de mmoire suffisante. En pratique, il conduira quand mme souvent une erreur dexcution, car lespace mmoire se retrouvera entirement occup. Les secondes sont dues un nombre toujours croissant dobjets morts non dsallous, qui occupent donc toujours de lespace. Si le programmeur modifie son programme pour retirer les maillons inutiles de sa liste chane, mais quil ne les dsalloue pas, le problme nest pas rgl. Dun autre ct, cette distinction peut savrer assez artificielle selon les langages et les modles de programmation considrs. En effet, en prsence darithmtique de pointeurs, la notion dobjet est difficile dfinir, puisquun objet peut revenir la vie. Inversement, un

objet qui reste indfiniment accessible (au sens du graphe du tas), mais que le programme ne va plus jamais utiliser, ne mrite pas vraiment le qualificatif de . Dans tous les cas, le problme des fuites de mmoire est omniprsent dans les projets de dveloppement logiciel, car il est la source de nombreuses erreurs dexcution trs difficiles reproduire, donc liminer.

Fragmentation du tas Gestionnaires mmoire Indpendamment des difficults de


programmation quelle introduit, la gestion manuelle de la mmoire dynamique nest de toute faon pas adapte lembarqu temps-rel. En effet, le modle mmoire sous-jacent souffre dun phnomne de progressive qui mne des comportement temporels impossibles matriser. Le problme se manifeste lorsque lexcution du programme se prolonge : au fur et mesure des allocations et des dsallocations, les zones libres et occupes sparpillent dans lensemble du tas, jusqu constituer un vrai gruyre. Linconvnient de cette situation est que le systme peut se retrouver dans lincapacit de satisfaire une requte dallocation alors que la quantit de mmoire disponible est bien prsente, mais quil ny a cet instant aucun bloc contigu de taille suffisante. Ce phnomne est illustr sur la figure 1 Le tas initial est entirement libre en (a). Le programme demande ensuite une zone de taille gale 50% du tas, le gestionnaire mmoire lui alloue donc la premire moiti de la mmoire (en gris) et on obtient le tas (b). Le programme demande ensuite une zone de taille 25%, et on obtient le tas (c). Un problme de fragmentation apparat lorsque le programme libre la premire zone quil avait alloue. On obtient le tas (d), dans lequel lespace libre (en blanc) est . Bien que 75% de lespace soit disponible, le gestionnaire mmoire ne peut pas satisfaire une demande dallocation de cette taille, car il ny a pas en mmoire de zone assez grande.
(a) (b) (c) (d) Fig. 1 Fragmentation progressive de la mmoire au fur et mesure des allocations et des librations.

Pour lutter contre ce problme, les diffrents utilisent des stratgies heuristiques censes rduire la fragmentation. Par exemple, dans le choix du bloc libre rserver pour satisfaire une allocation, on peut citer les stratgies , qui consiste choisir le premier bloc assez grand, et , qui recherche le bloc le plus ajust. La seconde est beaucoup moins rapide, mais provoque moins de fragmentation. Un autre moyen de lutte contre la fragmentation est de des blocs libres adjacents, de faon dfragmenter le tas au moment des dsallocations. Il existe ainsi une diversit trs importante dalgorithmes de gestion mmoire . Ces diffrentes techniques ont une efficacit trs variable , mais mme les plus efficaces ne visent que la performance globale, sans souci de la des temps de rponse. Leur usage dans un contexte temps-rel est donc problmatique, car il est en pratique impossible de prdire fidlement le comportement temporel au pire cas de lallocation.

3.

Recyclage automatique de la mmoire

Lutilisation de mmoire dynamique offre un confort de programmation considrable, mais comme nous lavons vu, la libration manuelle des zones inutilises est souvent trop difficile. Lalternative consiste confier entirement la tche de la gestion mmoire lenvironnement dexcution. Le programmeur doit toujours rserver, explicitement ou non, la mmoire quil veut utiliser, mais il na plus se proccuper de la librer, elle est rcupre automatiquement. Le terme anglais (GC, parfois traduit par , ou ) dsigne lensemble des techniques permettant dautomatiser cette dtection des zones mmoires inutilises ( ) en vue de leur rutilisation . Le concept (ainsi que le nom) de provient des premires implantations du langage Lisp, dans les annes 60 . En effet, le Lisp est un langage , qui ne fait pas de distinction entre les donnes et le code du programme, indiffremment reprsents en mmoire par des listes chanes. Entre autres innovations, le Lisp est un langage dit , cest dire que lexcution dun programme peut inclure la cration la vole de nouvelles fonctions, grce la prsence dun interprteur dans lenvironnement dexcution. Lallocation y est donc implicite, et les dures de vie des diffrents objets ne suivent pas de scnario particulier. Lallocation en pile ou la dsallocation manuelle ne sont donc pas utilisables dans ce contexte. Pour rsoudre le problme de la gestion mmoire, les auteurs du ont donc dcid de dcharger compltement le programmeur de cette tche, et de la confier lenvironnement dexcution. Les allocations et les dsallocations se font de faon transparente. Lorsque le systme arrive court despace et ne peut plus satisfaire une requte dallocation, il interrompt le programme, et parcourt la mmoire pour reprer et recycler les blocs inutiliss.

3.1.

Principe

Lobjectif dun ramasse miettes est de dterminer, parmi lensemble des objets prsents en mmoire, lesquels sont encore vivants et lesquels sont devenus inaccessibles, de faon lespace occup par les objets morts. Ainsi, lenvironnement dexcution se rapproprie automatiquement la mmoire lorsque le programme ne lutilise plus. Cette section prsente le principe gnral des deux techniques principales utilises cet effet : le marquage-balayage, et le comptage de rfrences. Il en existe bien sr dinnombrables variantes et amliorations, comme nous le verrons plus tard, mais tous les ramasse-miettes utilisent une combinaison de ces deux techniques . La premire nettoie priodiquement le tas, tout en prenant soin de conserver les objets vivants. La seconde cherche plutt dtecter la mort des objets pour les recycler sur-le-champ.

3.1.1.

Marquage - Balayage

Chronologiquement, la premire technique propose pour caractriser les objets vivants est celle dite du marquage-balayage (ou ). Elle dcoule directement de la dfinition rcursive d que nous avons adopte : un objet est vivant sil est point par une racine ou par un autre objet vivant. Lorsque le systme narrive pas satisfaire une requte dallocation cause du manque de mmoire, il suspend lexcution du programme utilisateur et entame un cycle de collecte. Le ramasse-miettes commence par rcursivement les objets accessibles depuis les racines, cest dire les variables globales et les pointeurs prsents dans la pile dexcution. Chaque fois quun objet est parcouru, il est pour mmoriser quil est accessible. Lorsque lalgorithme ne dcouvre plus dobjets marquer, cest quil a parcouru lensemble des objets vivants. La

seconde phase de la collecte consiste alors tous les objets non marqus.

lensemble du tas, en rcuprant au passage

Inventaire des racines

Pour pouvoir parcourir le graphe du tas, il est ncessaire den connatre les racines, cest dire les variables globales et locales du programme. Pour faire linventaire de ces dernires, le ramasse-miettes doit parcourir la pile dexcution, et dterminer pour chaque mot sil sagit dune valeur scalaire ou dune rfrence. Suivant le contexte, cette opration peut tre dune complexit trs variable . Dans le contexte dun langage interprt comme Java, la tche est relativement simple. La pile dappels est entirement sous le contrle de la machine virtuelle, il est donc possible de dterminer le type des valeurs quelle contient. A linverse, pour un langage compil faiblement typ, comme le C, labsence dinformations de typage complique considrablement lopration de recherche de pointeurs. Il faut donc examiner avec prudence lensemble des variables de la pile, mais galement les registres du processeur.

Marquage La phase de marquage suppose de parcourir rcursivement lensemble des objets


vivants, en commenant par les objets points directement par les racines, puis en suivant leurs champs de type pointeur, et ainsi de suite. L encore il faut pouvoir diffrencier, lintrieur dun objet, un pointeur dune valeur scalaire, ce qui est plus ou moins difficile suivant la sophistication de lenvironnement dexcution et le langage de programmation considr. Lalgorithme de parcours doit les objets dj atteints pour ne pas les traiter plusieurs fois. Chaque objet doit donc contenir un emplacement (au moins un bit) permettant denregistrer cette information.

Balayage

Une fois que le marquage a parcouru tous les objets vivants, ceux qui restent sont rputs morts ( ). Pour les dsallouer, le ramasse-miettes le tas dun bout lautre, la recherche dobjets dont le bit de marquage na pas t positionn. Au passage, il efface aussi la marque des objets vivants, de faon prparer le prochain cycle de collecte.

Remarques

La notion de ramasse-miettes, ainsi que lalgorithme de marquage-balayage, sont indpendants du modle mmoire sous-jacent, et en particulier de la reprsentation des zones libres et occupes. un objet signifie donc simplement signaler au gestionnaire mmoire que cette zone est maintenant disponible pour lallocation. Le gestionnaire mmoire doit donc faire face la problmatique de la fragmentation, et aux performances temporelles imprvisibles associes.

Temps de pause

Pendant son parcours de la mmoire, le ramasse-miettes interrompt temporairement lexcution du programme. Cette interruption, appele , est susceptible dintervenir allocation, et son temps dexcution au pire cas est trs important car il inclut le pire cas du parcours de la pile, le pire cas du marquage et le pire cas du balayage. Du point de vue du programme, utiliser un tel ramasse-miettes pour grer la mmoire implique donc un temps dexcution au pire cas de lallocation trs long. Bien sr, en pratique, la plupart des allocations seront excutes en un temps beaucoup plus court, mais dans un contexte temps-rel, on ne retiendra que le pire cas, souvent insatisfaisant.

3.1.2.

Comptage de rfrences

A linverse du marquage-balayage, un ramasse-miettes comptage de rfrences ne compte pas sur un parcours exhaustif du tas pour reconnatre les objets vivants, mais garde trace, chaque modification de pointeur, de linformation daccessibilit.

Lide est de comptabiliser, pour chaque objet, le nombre dobjets vivants qui pointent directement sur lui. Ce , un champ supplmentaire ajout chaque objet, est mis jour automatiquement chaque fois quun pointeur, y compris les racines, est dirig vers lobjet. Lorsque le compteur dun objet tombe zro, cela signifie que le dernier pointeur vers lui vient dtre retir. Lobjet peut alors tre dsallou, et donc le compteur de rfrences de tous les objets quil pointait doit tre dcrment, et ainsi de suite. Cette technique permet de dtecter plus prcisment le moment o un objet cesse dtre accessible que par marquage-balayage, par contre elle ncessite un entier supplmentaire par objet, ce qui constitue un surcot important. De plus, cette dsallocation est rcursive, et donc risque de prendre un temps imprvisible. Les provoqus par un ramasse-miettes comptage de rfrences sont donc associs non plus aux allocations mais aux critures de pointeurs. Comme pour le ramasse-miettes marquage-balayage, ils sont susceptibles dintervenir sur criture de pointeurs, et de durer un temps imprvisible.

Barrires en criture

La mise jour du compteur de rfrences doit se faire automatiquement, sans que le programmeur nait sen proccuper. Chaque criture de pointeur, puisquelle modifie les relations daccessibilit, doit donc saccompagner de lajustement de compteurs : ceux des objets points respectivement avant et aprs la modification. Cette modification de la smantique du langage est dsigne sous le nom de ( ). Dans une machine virtuelle, ajouter une barrire signifie simplement modifier linterprtation de linstruction dcriture de champ. Par contre, dans un langage compil, il faut que le compilateur mette du code assembleur chaque criture pour raliser la barrire. Lutilisation de barrires permet de rpartir naturellement la tche de comptabilit tout au long de lexcution. Cependant, elles ajoutent un surcot important aux oprations mmoire : chaque criture de pointeur est accompagne de deux critures de compteur. Lexcution de lensemble du programme peut sen trouver considrablement ralentie. En consquence, de nombreuses techniques ont t proposes pour rduire autant que possible le nombre de barrires ajoutes dans le programme. Par exemple, le ( ) est une technique doptimisation qui consiste retirer automatiquement certaines barrires lors de la compilation, typiquement celles lies aux variables locales, lorsque le compilateur est sr quelles sont inutiles ou redondantes. La limitation principale du comptage de rfrences est pourtant dune autre nature : lui seul, un ramasse-miettes simple comptage de rfrences est incapable de dtecter les structures de donnes cycliques inaccessibles . Alors quau premier abord, cette limitation peut paratre mineure, elle est dune importance considrable en pratique, car de nombreuses structures de donnes usuelles produisent des graphes dobjets fortement connexes. Par exemple, dans la figure 2, la liste doublement chane o2 o3 o4 est initialement accessible seulement via lobjet o1 . Les compteurs de rfrences sont reprsents sur la gauche des objets : on suppose que lobjet o1 est vivant, et quil est directement point par n objets. Le programme effectue une opration qui retire le lien de o1 vers o2 (par exemple en effaant le pointeur, ou en lui affectant une nouvelle cible), rendant donc la liste o2 o3 o4 inaccessible. cause du pointeur venant de o3 , le compteur de rfrences de o2 ne tombe pas 0 mais seulement 1, et donc le ramasse-miettes ne se rend pas compte que la liste entire est maintenant inaccessible. Cette limitation est un dfaut majeur de la technique de comptage de rfrences, car si un programme gnre beaucoup de structures cycliques inaccessibles, elles ne seront jamais dsalloues et la fuite de mmoire finira par provoquer une faute dexcution. Pour cette raison, un ramasse-miettes comptage de rfrences nest jamais utilis seul, mais est toujours par un autre ramasse-miettes, par exemple marquage-balayage . Le second ramasse- miettes est dclench lorsque la mmoire est puise, de faon rcolter les cycles dobjets morts

Collecte des structures cycliques

o3

o3

avant

1 aprs

o4

o4

Fig. 2 Comptage de rfrences dans une structure cyclique : aprs leffacement du pointeur, lobjet o1 ne pointe plus sur o2 , mais le compteur de rfrences de o2 reste 1. que le comptage de rfrences a omis.

3.2

Variantes ralistes

Les techniques abordes dans la section prcdente ont t prsentes jusquici de faon assez simpliste, et ne sont pas reprsentatives des ramasse-miettes actuels. En particulier, elles ne sont efficaces ni en termes de comportement temporel, ni doccupation de la mmoire. Dans cette section, on va sintresser quelques amliorations que lon peut apporter ces techniques pour en amliorer les performances.

3.2.1

Ramasse-miettes concurrents et incrmentaux

Parmi les dfauts les plus reprochs aux ramasse-miettes, a longtemps figur limportance excessive des infligs au programme de lutilisateur . En effet, les techniques de collecte naves ncessitent dinterrompre lexcution du programme pendant la totalit du cycle de collecte ( ). Par exemple, le ramasse-miettes marquage-balayage prsent la section 3.4.1.1 doit parcourir lintgralit des objets vivants puis balayer lensemble du tas avant de rendre la main lapplication. Cette faiblesse est particulirement problmatique dans un contexte temps-rel, par exemple lorsque le programme est soumis des contraintes de temps de rponse : si le processeur est monopolis par le ramasse-miettes, le systme ne peut pas traiter une ventuelle requte. Sil abandonne au contraire le cycle de collecte, il devra le reprendre de zro, et le problme se pose nouveau. En effet, lexcution du ramasse-miettes doit se faire de manire atomique.

Le ramasse-miettes et le corrupteur

Pour pallier ce problme sont apparues les premires propositions de ramasse-miettes , cest dire excuts en parallle de lapplication . Pour obtenir un paralllisme rel, il faut disposer de plusieurs processeurs, et rserver lun dentre eux lactivit du ramasse-miettes. Cette possibilit est assez rare dans le monde des systmes embarqus, o les ressources en puissance de calcul sont plus contraintes. Dans un contexte mono-processeur, le paralllisme est simul par lentrelacement des tches, et on parle alors de ramasse-miettes . Un ramasse-miettes incrmental neffectue donc pas son cycle de collecte en une seule fois, et par consquent il doit tenir compte des modifications que le programme utilisateur apporte entre-temps aux objets du tas. On peut ainsi parler de (le terme anglais est ) pour dsigner le programme applicatif par opposition au ramasse-miettes, car il le tas linsu de ce dernier.

o2

o1

o1

o2

Lide dentrelacer lexcution du programme et du ramassemiettes peut galement sappliquer au comptage de rfrences : en effet, de par sa nature rcursive, la tche de dsallocation associe la mort dun objet peut tre lorigine dun temps de pause consquent. La dsallocation paresseuse est une technique qui permet de limiter cette quantit de travail : chaque fois quun objet devient inaccessible, il nest pas dsallou directement mais simplement mmoris sur une pile spcifique (la ), sans sintresser son contenu. Lors de la prochaine allocation, le systme va piocher un objet libre sur le sommet de la , et cest seulement ce moment quil va parcourir ses champs et dcrmenter les compteurs des des objets rfrencs. Si un compteur tombe alors zro, lobjet correspondant est son tour empil sur la . Cette technique permet dviter les temps de pause ds aux dsallocations en cascade. Par exemple, si le programme retire le dernier pointeur vers un objet qui se trouve tre la racine dun arbre, la dsallocation rcursive pratique par un ramasse-miettes naf comptage de rfrences va librer lobjet, parcourir ses champs, dcrmenter les compteurs des objets rfrencs, qui vont donc tomber zro, et ainsi de suite. La dsallocation paresseuse va uniquement empiler la racine sur la , et les objets ne seront librs quau fur et mesure des allocations suivantes. Le travail de dsallocation se trouve donc naturellement rparti tout au long de lexcution de lapplication.

Dsallocation paresseuse

3.2.2

Ramasse-miettes compactants

Les ramasse-miettes prsents jusquici souffrent dun problme dj rencontr par les gestionnaires mmoire explicites, celui de la fragmentation. En effet, au fur et mesure que des blocs de mmoire sont allous et librs, il devient de plus en plus coteux de rechercher les blocs libres, et une allocation peut mme chouer par manque dune assez grande zone libre contigu. Pour viter ce phnomne, certains ramasse-miettes prennent le parti de les objets de faon dfragmenter le tas.

Ramasse-miettes copie Lexemple le plus simple de ramasse-miettes compactant est celui dit ( ). Le principe est de diviser le tas en deux moitis, lune contenant les donnes actives (le ), et lautre tant laisse en jachre (le ). Lallocation ne requiert plus la recherche dun bloc libre, mais se fait , cest dire simplement en dcalant un curseur dans le . Chaque fois quun objet est allou, on dcale dautant le curseur qui indique o commence lespace libre, cest dire qui pointe au sommet du tas.
racine sommet_du_tas

fromspace

o1

o2 o3

o4

o5

o6

o7

o8

tospace

Fig.3 Ramasse-miettes copie. Le programme demande lallocation dun objet de mme taille que o8, mais il ny a plus assez despace libre (en gris).

Le cycle de collecte se dclenche lorsque le est plein, et quil nest plus possible dy allouer un nouvel objet (figure 3). Comme dans un ramasse-miettes marquage-balayage, les objets vivants sont alors parcourus partir des racines, mais la place dtre marqus, ils sont dans le , en le remplissant au fur et mesure (figure 3). Cette opration

est dlicate, car elle implique de modifier le contenu des objets et des variables locales actives pour rectifier la destination des pointeurs et prserver la cohrence du tas.
racine sommet_du_tas

fromspace

o1

o 2 o3

o4

o5

o6

o7

o8

tospace

o1

o3

o6

Fig. 4 Ramasse-miettes copie. Le ramasse-miettes est en train de transfrer les objets vivants dans le . Lobjet o6 a dj t copi, mais tel quel : il pointe encore sur o2 dans le . Lorsque o2 aura t copi, ce pointeur sera rectifi. Une fois que lensemble des objets a t copi, le rle des deux demi-espaces est chang (figure 4). Tous les objets morts sont donc abandonns sans prcautions dans lancien . Lexcution du programme est relance de faon transparente, les prochaines allocations se faisant au sommet du nouveau tas.
racine

tospace

o1

o2 o3

o4

o5

o6

o7

o8

fromspace

o1

o3

o6

o2 sommet_du_tas

Fig. 5 Ramasse-miettes copie. Les deux demi-espaces ont t changs. Les besoins dallocation du programme peuvent maintenant tre satisfaits (espace libre en gris).

La ncessit de diviser la mmoire en deux est parfois trop contraignante lorsque lespace disponible est rduit, comme par exemple dans un contexte embarqu. La variante dite se soustrait ce problme en dplaant un un les objets vivants la base du tas. Contrairement la technique de copie, ce compactage doit dans un premier temps parcourir lensemble du tas pour dterminer les objets vivants, et ne pas les craser lors de la copie des objets. Un cycle de collecte est illustr dans la figure 6. Au dbut du cycle , le tas est entirement occup. Le ramasse-miettes parcourt alors le tas pour marquer les objets vivants , car la dfragmentation va ici soprer par balayage, et non pas rcursivement comme avec un ramasse-miettes demi-espaces. Le balayage alors les objets vivants au dbut du tas , tout en modifiant les champs des objets pour quils pointent sur les mmes objets quavant la collecte.

Ramasse-miettes marquage-compactage

Ramasse-miettes gnrationnels

Les diffrents types de ramasse-miettes traage prsents ci-dessus sparent, chaque collecte, les objets vivants des objets morts. Pourtant, dune collecte lautre, une bonne partie des objets vivants restent les mmes, mais ils doivent cependant tre parcourus, marqus ou copis comme les autres. L , base sur des observations empiriques, suppose mme que la plupart des objets meurent jeunes, et donc que les objets plus vieux ont toutes les chances de le devenir encore plus. Il parat donc sens de sattacher en priorit aux objets jeunes, puisque ce sont les plus susceptibles de se changer en espace libre lors des collectes. A cet effet, un ramasse-miettes distingue plusieurs zones diffrentes dans le tas : la (ou ), o sont

racine

sommet_du_tas

(a)

o1

o 2 o3

o4

o5

o6

o7

o8

racine

sommet_du_tas

(b)

o1

o 2 o3

o4

o5

o6

o7

o8

racine

sommet_du_tas

(c)

o1

o2 o3

o6

Fig. 6 Ramasse-miettes marquage-compactage. En , le tas avant collecte ; en , le tas aprs marquage, les objets morts (non marqus) sont reprsents en gris ; en , le tas aprs compactage.

allous les nouveaux objets, et une ( , ou ), o se trouveront les objets rputs vieux. Les allocations se font dans la crche, par un simple dcalage de curseur. Lorsque lespace est puis, le ramasse-miettes entreprend une : il parcourt la crche en commenant par les racines, et dplace les objets vivants dans lancienne gnration. Cette opration est appele ( ) : si des objets ont survcu jusqu la collecte mineure, ils sont dans la zone principale. La collecte des objets morts de la crche requiert bien sr un calcul daccessibilit dans le graphe du tas tout entier, et donc le ramasse-miettes doit tenir compte des pointeurs entre les gnrations. Pour ne pas avoir parcourir lensemble du tas chaque collecte mineure, les pointeurs provenant de lancienne gnration font lobjet dun traitement spcial : ils sont considrs directement comme des racines lors du parcours de la crche. Pour dtecter ces pointeurs, un ramasse-miettes gnrationnel a besoin dune barrire en criture : chaque fois que le programme cre un pointeur dun vieil objet vers un jeune objet, lenvironnement dexcution copie ce pointeur dans une zone ddie que le ramasse-miettes ajoutera son ensemble de racines lors de la phase de marquage. Par exemple, dans la figure 7, lespace libre de crche est puis, et le ramasse-miettes va entamer une collecte mineure. Les deux seules racines du tas sont les variables r1 et r2, mais la barrire en criture a intercept lcriture dans o5 du pointeur vers o7 , et a copi le pointeur dans les racines de la crche. Par contre, le pointeur de o8 vers o6 nest pas intressant : o6 est dj dans lancienne gnration, et donc nest pas affect par les collectes mineures.
r1 racines de la crche r2 o7 o8 o9 o10

o1 o3 o4

o2

o5 o6

ancienne gnration

crche

Fig. 7 Ramasse-miettes gnrationnel. La crche est entirement occupe, et va subir une collecte mineure. Les objets survivants seront dplacs dans lancienne gnration.

La crche est collecte en utilisant une technique de copie : au fur et mesure du parcours,

les objets vivants (o7 , o9 , o10 ) sont dplacs dans lancienne gnration. Le tas obtenu aprs la collecte est reprsent sur la figure 8 : lespace de la crche est maintenant considr comme libre (o8 a t libr implicitement lorsque le pointeur a t rinitialis) et le programme utilisateur peut tre relanc. On remarquera que o3 et o6 nont pas t collects : ce sont des objets morts de lancienne gnration, et il faudra attendre la prochaine collecte majeure, lors de laquelle lensemble du tas sera parcouru, pour sapercevoir quils sont inaccessibles.
r1 racines de la crche r2

o1 o3 o4

o2

o5 o6 o9

o7 o10

ancienne gnration

crche

Fig. 8 Ramasse-miettes gnrationnel aprs une collecte mineure. La crche est entirement disponible, et tous les objets restants sont situs dans lancienne gnration.

Conclusion

cause de la nature rcursive des tches quils ont accomplir, les algorithmes de ramasse- miettes prsentent souvent des comportements temporels difficiles prvoir. De nombreuses optimisations ont t proposes pour amliorer leurs performances, en particulier dans le but de rduire les temps de pause infligs lexcution. En particulier, des ramasse-miettes incrmen- taux sont continuellement prsents comme , puisquils permettent de le travail en fragments de dure fixe. Cependant, il sagit le plus souvent dalgorithmes pour lesquels les temps de pause sont courts . Les temps dexcution au pire cas du ramasse-miettes, bien quils ne se produisent presque jamais en pratique, sont trop importants pour tre compatibles avec une politique dordonnancement temps-rel.