Certains collectionneurs supposent que tout ce qui se trouve sur la pile est un pointeur potentiel (comme Boehm GC). Cela s'avère finalement être moins grave que ce que l'on pourrait penser, mais c'est clairement sous-optimal. Plus souvent dans les langages gérés, des informations de balisage supplémentaires restent avec la pile pour aider le collecteur à déterminer où se trouvent les pointeurs.
Rappelez-vous que dans la plupart des langages compilés, la structure d'une trame de pile est la même à chaque fois que vous entrez dans une fonction, il n'est donc pas si difficile de garantir que vous balisez vos données de la bonne manière.
L'approche "bitmap" est une façon de faire cela. Chaque bit du bitmap correspond à un mot sur la pile. Si le bit est égal à 1, alors l'emplacement sur la pile est un pointeur, et s'il est égal à 0, alors l'emplacement est juste un nombre du point de vue du collecteur (ou quelque chose du genre). Le runtime GHC extrêmement bien écrit et les conventions d'appel utilisent une mise en page d'un mot pour la plupart des fonctions, de telle sorte qu'il suffit de quelques bits pour indiquer la taille de la trame de pile, le reste servant de bitmap. Les trames de pile plus grandes nécessitent une structure multi-mots, mais l'idée est la même.
L'intérêt est que le surcoût est faible, car les informations de mise en page sont calculées à la compilation, puis incluses dans la pile à chaque appel de fonction.
Une approche encore plus simple est le "pointeur en premier", où tous les pointeurs sont situés au début de la pile. Vous n'avez besoin d'inclure qu'une longueur avant les pointeurs, ou un mot "fin" spécial après eux, pour indiquer quels mots sont des pointeurs selon cette disposition.
De manière intéressante, essayer de placer ces informations de gestion sur la pile pose tout un tas de problèmes liés à l'interopérabilité avec le C. Par exemple, il est sous-optimal de compiler des langages de haut niveau en C, car même si le C est portable, il est difficile d'inclure ce type d'informations. Les compilateurs d'optimisation conçus pour des langages de type C (GCC, LLVM) peuvent restructurer la trame de pile, posant des problèmes, donc le backend GHC LLVM utilise sa propre "pile" plutôt que la pile LLVM, ce qui lui fait perdre certaines optimisations. De même, la frontière entre le code C et le code "géré" doit être construite avec soin pour éviter de perturber le GC.
Pour cette raison, lorsque vous créez un nouveau thread sur la JVM, vous créez en réalité deux piles (une pour Java, une pour le C).