veilletech.fr
5 sept. Feed du jour
#04 BUN Article

Bun 1.4.1 : la mémoire au repos s'effondre

Un giga trois au repos devenu cent quarante-deux méga. Sans changer une ligne.

Bun 1.4.1 ferme 202 tickets. Le gain principal est la mémoire au repos : JavaScriptCore libère le code généré par le JIT après une inactivité prolongée, et un serveur Next.js SSR retombe à 142 Mo de RSS contre 222 Mo en 1.4.0, 1 303 Mo en 1.3.14 et 195 Mo sous Node.js 26. S'y ajoutent HTTP/2 dans Bun.serve sur le même port que HTTP/1.1, et bun install --offline.

3 min de lectureintermédiairevidéo 1:17
Partager
Sommaire5 sections
  1. Ce qui se passe
  2. La mémoire au repos
  3. HTTP/2 dans Bun.serve
  4. Ce que ça change ailleurs
  5. À retenir

Ce qui se passe

Bun 1.4.1 corrige 202 tickets. Derrière ce décompte de version mineure, trois changements méritent qu'on s'arrête.

La mémoire au repos

C'est le résultat le plus marquant de la version. JavaScriptCore supprime désormais le code produit par le compilateur à la volée après une période d'inactivité prolongée — ce qui change tout pour un processus de longue durée qui alterne charge et creux.

Mesures de l'équipe (RSS après 60 s de charge puis 3 minutes d'inactivité, Linux x64) :

Application Bun 1.4.1 Bun 1.4.0 Bun 1.3.14 Node.js 26
Next.js SSR 142 Mo 222 Mo 1 303 Mo 195 Mo
vite dev 111 Mo 142 Mo 292 Mo 115 Mo
Express 53 Mo 65 Mo 76 Mo 83 Mo
Fastify 55 Mo 65 Mo 78 Mo 89 Mo
Elysia 44 Mo 46 Mo 69 Mo 96 Mo
Hono 34 Mo 35 Mo 53 Mo 92 Mo

Deux lectures. La progression depuis 1.3.14 sur Next.js SSR — de 1 303 Mo à 142 Mo — corrige surtout une anomalie. Le point durable est ailleurs : Bun passe sous Node.js 26 sur les six applications mesurées, alors qu'il était encore au-dessus sur Next.js et vite dev en 1.3.14.

HTTP/2 dans Bun.serve

Bun.serve sert maintenant HTTP/2 sur le même port que HTTP/1.1, avec les mêmes routes et le même handler fetch ; req.url et req.body se comportent de façon identique sur les deux protocoles. Sur TLS, la négociation passe par ALPN ; en clair, un client qui envoie le préambule HTTP/2 est servi en HTTP/2. Pour refuser HTTP/1.x :

JavaScript
Bun.serve({ http1: false, fetch(req) { return new Response("ok"); } });

Le débit annoncé, sur un GET « Hello World » (Linux x64, 64 cœurs, h2load) : 291 512 req/s pour Bun.serve, contre 55 619 pour node:http2 exécuté dans Bun et 42 733 pour node:http2 sous Node.js 26 — soit 6,8× plus rapide.

La limite à connaître avant de basculer : les WebSockets et les trailers de réponse ne sont pas encore supportés en HTTP/2.

Ce que ça change ailleurs

Bun.write(path, response) écrit désormais le corps d'une Response, d'une Request ou d'un ReadableStream en flux vers le fichier au lieu de le charger en mémoire : un téléchargement de 128 Mio ajoutait 161 Mo au pic de RSS, il en ajoute maintenant 13 Mo. Dans la même logique, fetch() et les téléchargements S3 se mettent en pause quand 256 Kio de corps ne sont pas lus.

Côté installation, bun install accepte --offline et --prefer-offline, qui résolvent depuis le cache local sans contacter le registre — utile en intégration continue et dans une image de construction, où le réseau est le maillon lent.

Le client WebSocket gagne pause() et resume(), qui arrêtent et relancent les lectures sur la socket TCP sous-jacente. C'est une extension propre à Bun, absente des navigateurs : l'API WHATWG ne sait pas cesser de recevoir sans fermer la connexion, si bien que les messages qui arrivent plus vite qu'ils ne sont traités s'accumulent en mémoire. Socket en pause, Bun ne lit plus et le pair reçoit la contre-pression TCP.

S'y ajoutent crypto.argon2, le tree-shaking à travers les import() dynamiques, --compile --bytecode en compilation croisée, et des exécutables compilés plus petits et plus rapides à démarrer.

À retenir

  1. bun upgrade suffit ; le gain mémoire ne demande aucun changement de code.
  2. Si un proxy était placé devant Bun uniquement pour parler HTTP/2, il peut disparaître — sauf si vous servez des WebSockets par ce chemin.
  3. La compatibilité Node.js progresse sans être achevée : un projet qui dépend d'un module natif se teste avant de basculer.

Source : Bun