Author: Christian.Queinnec@lip6.fr

## 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 :

1. 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.
2. Fin du cycle du GC majeur.
   En cas d'échec on passe à l'étape 3.
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.
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).