Gestion mémoire en Objective CAML
Le GC d'Objective CAML est un GC qui combine les différentes techniques
rencontrées précédemment. C'est un GC à deux générations : les anciens et
les nouveaux. Il utilise principalement un Stop&Copy sur la
jeune génération (GC mineur) et un Mark&Sweep incrémentiel
sur la génération ancienne (GC majeur).
Un objet jeune qui survit à un GC mineur est déplacé dans la
génération ancienne. Le Stop&Copy utilise l'espace de la
génération ancienne comme espace to-space. Quand il a fini,
l'ensemble de l'espace from-space est complètement libre.
Lorsque nous avons présenté les GC à génération, nous avons
signalé la difficulté que présentent les langages fonctionnels
impurs : une valeur de l'ancienne génération peut référencer un
objet de la nouvelle génération. En voici un petit exemple :
# let
ancien
=
ref
[
1
]
;;
val ancien : int list ref = {contents=[1]}
(* ... *)
# let
jeune
=
[
2
;5
;8
]
in
ancien
:=
jeune
;;
- : unit = ()
Le commentaire (* ... *)
remplace une longue séquence de code
pendant laquelle ancien est passé dans l'ancienne
génération. Le GC mineur doit tenir compte de certaines valeurs
de l'ancienne génération. On doit donc tenir à jour une table des
références de l'ancienne génération vers la nouvelle qui fait partie
de l'ensemble des racines dont part le GC mineur. Cette table de
référence grossit très peu et elle devient vide juste après un GC
mineur.
Il est à noter que le Mark&Sweep de la génération ancienne
est incrémentiel. C'est-à-dire qu'une partie du GC majeur se déroule à
chaque GC mineur. Le GC majeur est un Mark&Sweep qui suit
l'algorithme présenté page ??.
L'intérêt de cette approche incrémentielle est de diminuer les temps
d'attente du GC majeur, en avançant la phase de marquage à chaque GC
mineur. Quand un GC majeur se déclenche, le marquage se termine sur
les parties non traitées et la phase de récupération est enclenchée.
Enfin comme le Mark&Sweep peut fragmenter de manière
importante la génération ancienne, un algorithme de compaction peut
être déclenché après le GC majeur.
On obtient au total les étapes suivantes :
-
GC mineur : effectue le Stop&Copy sur la
génération jeune, vieillit les objets survivants en les changeant
de zone et puis fait une partie du Mark&Sweep de la
génération ancienne.
Il échoue si le changement de zone échoue, on passe alors à l'étape 2.
- Fin du cycle du GC majeur.
En cas d'échec on passe à l'étape 3.
- GC majeur de nouveau, pour vérifier si des objets comptés
comme utilisés pendant les phases incrémentielles sont devenus libres.
En cas d'échec on passe à l'étape 4.
- Compaction de la génération ancienne pour obtenir un espace
contigu maximal. En cas d'échec de cette dernière phase, il ne reste
plus de possibilité et le programme échoue.
Le module GC permet de déclencher une des phases du GC.
Une dernière particularité de la gestion mémoire d'Objective CAML est
que l'espace du tas n'est pas alloué une fois pour toute en début de
programme, mais il évolue au cours du temps (augmentation ou diminution
d'une taille donnée).