Davantage de langages devraient adopter la vérification des fonctions sans allocation d’OxCaml
(theconsensus.dev)- OxCaml, le surensemble d’OCaml de Jane Street, permet de déclarer au compilateur avec
[@zero_alloc]qu’aucune allocation sur le tas n’est autorisée dans tout l’arbre d’appels d’une fonction - Si une allocation se produit sur le chemin d’appel déclaré, cela entraîne immédiatement un échec de compilation, ce qui permet d’empêcher plus vite les régressions qu’en les recherchant plus tard avec un profileur
- En C, C++, Java, Go, C#, Rust, Zig, OCaml, etc., l’approche consiste généralement à repérer avec un profileur les allocations sur les hot paths pour les réduire
- Le code des hot paths peut recréer des allocations à la moindre petite modification ; si l’on oublie le contexte des optimisations existantes, il faut recommencer la même enquête
- Les conventions de passage d’allocator en Zig ou dans certaines parties du Rust moderne aident aussi, mais une vérification par le compilateur constitue une protection plus directe qu’une simple convention
Ce que change [@zero_alloc] dans la gestion des allocations
- OxCaml est un surensemble d’OCaml de Jane Street, qui permet d’affirmer qu’une fonction n’effectue pas d’allocation sur le tas
- En ajoutant
[@zero_alloc]à une fonction, le compilateur vérifie l’absence d’allocations sur le tas non seulement dans cette fonction, mais aussi dans tout l’arbre d’appels en dessous - Si une allocation se produit dans l’arbre d’appels, le build échoue et le compilateur signale l’allocation
- Il serait sans doute possible de construire une vérification similaire par analyse statique, mais parmi les langages grand public, il est rare qu’une telle fonctionnalité soit intégrée directement au compilateur sur la base de résumés générés
La différence avec l’approche centrée sur le profileur
- Dans les autres langages, on commence généralement par repérer les allocations avec un profileur, puis on les supprime ou les réduit, en particulier dans les boucles exécutées des millions de fois
- C, C++, Java, Go, C#, Rust, Zig et OCaml sont cités comme exemples de cette approche centrée sur le profileur
- Il suffit de modifier une seule ligne sur un hot path pour réintroduire des allocations, puis il faut revenir au profileur pour en retrouver la cause
- En Zig ou dans certaines parties du Rust moderne, on peut réduire les régressions en évitant de passer l’allocator aux fonctions, mais cela repose sur une convention
- La différence de
[@zero_alloc]est que, plutôt qu’une analyse a posteriori ou des règles d’équipe, le compilateur bloque les régressions d’allocation au moment du build
1 commentaires
Commentaires sur Lobste.rs
Je pensais que la raison pour laquelle Zig passe un allocator en argument de fonction était d’empêcher les fonctions qui ne reçoivent pas d’allocator en argument de faire des allocations sur le tas ; je me demande si c’est bien ça.
Si l’affirmation « les conventions peuvent être ignorées » est vraiment juste, cela semble aller à l’encontre de l’intention.
On peut créer un nouvel allocator à l’intérieur d’une fonction, comme on le ferait à l’extérieur.
Lien cadeau : https://theconsensus.dev/p/2026/…
nogc, et j’estime que sa sémantique est similaire dans la mesure où le GC se charge des allocations.https://dlang.org/phobos/dmd_nogc.html
Des exceptions nogc ont aussi été ajoutées expérimentalement à une époque, mais je n’ai pas vérifié leur état actuel ni leur implémentation.
https://dlang.org/changelog/2.079.0.html#dip1008
En Rust, n’utiliser que core est aussi une façon d’éviter les allocations.
Cette approche revient plutôt, au final, à « maîtriser ses dépendances » ou à « vérifier manuellement tout le graphe d’appels ».
Le point central de l’article est la manière dont un outil comme le compilateur peut imposer statiquement certaines propriétés et fournir un workflow productif pour repérer les endroits où elles sont enfreintes.
D a
@nogc, et ensuite il s’agit simplement de n’utiliser que des abstractions directement contrôlables avec des schémas d’allocation explicites.Puisqu’on a perdu la capacité à donner aux articles des titres descriptifs, j’ajoute que l’idée clé est de pouvoir annoter une fonction avec
[@zero_alloc]et de faire en sorte que le compilateur rejette le programme si l’arbre d’appels de cette fonction touche au tas.Je me demande si ce genre d’approche pourrait aussi s’appliquer à diverses conditions comme « ne lève pas d’exception ou ne panique pas », « sans verrou » ou « termine toujours ».