Java natif : quand oui, quand non et que choisir en cloud native
Par Dorian Chávez · fondateur de Hábil et architecte d'intégration ·
GraalVM, Quarkus, Spring Boot, cache de démarrage de Java 25 et CRaC : gains et coûts de chaque option, et laquelle choisir selon votre service et votre cloud.
Dans presque toutes les conversations sur les microservices Java revient la même question : les compile-t-on en natif ? La promesse paraît irrésistible : des services qui démarrent en une fraction du temps et utilisent une fraction de la mémoire. Et elle est vraie, avec des petits caractères que presque personne ne lit : ce que l'on gagne en démarrage et en mémoire se paie en capacité de traitement, en temps de compilation et en complexité d'exploitation.
Cet article s'adresse à celles et ceux qui décident comment se construisent et s'exécutent les services Java d'une banque, d'un assureur, d'une enseigne de retail ou de toute entreprise réglementée. Il répond à trois questions : quand le natif convient et quand il ne convient pas, que faire si votre service est nouveau ou s'il tourne déjà sous Spring Boot, et ce qui convient dans une architecture cloud native.
D'abord, ce que signifie « natif »
Un service Java ordinaire s'exécute sur la JVM, la machine virtuelle Java. Il démarre, charge ses classes et, pendant qu'il traite des requêtes, un compilateur interne (le JIT) optimise peu à peu le code le plus utilisé. C'est pourquoi un service Java met du temps à « chauffer » : il est lent les premières secondes, puis très rapide.
Compiler en natif —avec GraalVM Native Image— fait tout ce travail en amont, au moment de la construction. Le résultat est un exécutable qui n'a plus besoin de la JVM : il démarre beaucoup plus vite et utilise beaucoup moins de mémoire. En contrepartie, le compilateur doit connaître à l'avance tout ce que le programme peut faire (on appelle cela le « monde fermé »), et il perd la capacité de continuer à optimiser avec la charge réelle.
Entre ces deux extrêmes, il existe des options intermédiaires qu'il convient de comparer avant de décider :
- Le cache de démarrage de Java (projet Leyden). Java 24 a introduit le chargement et la liaison anticipés des classes et Java 25 a ajouté l'ergonomie et les profils ; grâce à eux, la JVM peut enregistrer dans un fichier le travail de chargement et de liaison des classes ainsi que les profils d'une exécution d'entraînement, et le réutiliser au démarrage. Le cache dépend de l'application, du JDK, du système d'exploitation et de l'architecture. C'est toujours la JVM habituelle, avec son JIT ; elle démarre plus vite et, dans le laboratoire de Quarkus, a aussi utilisé moins de mémoire [1][2][3].
- Enregistrer et restaurer un processus déjà chaud. CRaC, un projet d'OpenJDK disponible dans certaines distributions de Java, et AWS Lambda SnapStart prennent une « photo » de l'application déjà démarrée et la restaurent. CRaC peut restaurer très vite ; SnapStart peut ramener le démarrage à froid de Lambda à moins d'une seconde dans des scénarios favorables (chiffre d'AWS ; il dépend de l'application, de la plateforme et de la charge), sous conditions sur l'état, les connexions et les identifiants [4][5].
Ce que disent les mesures
La comparaison publique la plus complète des trois modalités est publiée par le projet Quarkus lui-même dans son guide officiel, avec un service de test [6]. C'est un laboratoire d'un fournisseur, avec une charge précise ; elle se lit donc comme un ordre de grandeur, non comme une promesse :
| Modalité | Temps jusqu'à la première requête | Débit maximal (requêtes par seconde) | Mémoire résidente (RSS) |
|---|---|---|---|
| JVM classique | ~4,4 s | ~13 300 | ~304 MiB |
| JVM avec cache de démarrage (Leyden) | ~1,9 s | ~12 400 | ~240 MiB |
| Natif (GraalVM) | ~0,6 s | ~5 400 | ~95 MiB |
Chiffres du laboratoire du projet Quarkus (fournisseur) : exécution du 21 avril 2026 avec Quarkus 3.34.3, JDK 25.0.2, GraalVM 25.0.2, 4 CPU et `-Xmx512m`. La mémoire résidente est la RAM que le processus garde occupée ; le débit maximal est la capacité maximale sous cette charge, et non celle de votre production ; et le temps jusqu'à la première requête n'est ni le temps de déploiement ni la latence que ressent votre client.
Trois lectures qui comptent plus que les chiffres :
- Dans ce laboratoire, le natif a atteint la première requête environ sept fois plus tôt et a utilisé près d'un tiers de la mémoire.
- Mais il a traité environ 40 % des requêtes par seconde de la JVM. Dans un service de longue durée à charge constante, la JVM peut offrir plus de débit soutenu, car son JIT optimise avec ce qui se passe réellement en production ; Oracle GraalVM propose l'optimisation guidée par profils (PGO) pour réduire cet écart, mais elle n'est pas disponible dans l'édition Community : confirmez l'édition et la licence, car ce laboratoire ne l'a pas mesurée [6][7]. Le résultat dépend de la charge, du CPU, du ramasse-miettes et de la configuration.
- Le cache de démarrage conserve une bonne partie de l'avantage en coûtant peu : un démarrage plus de deux fois plus rapide, presque le même débit et, ici, une mémoire passée de 304 à 240 MiB (l'effet peut varier et le cache ajoute environ 198 Mo à l'artefact). OpenJDK utilise l'application d'exemple de Spring (PetClinic) comme étude de cas du cache ; aucune étude de cas ne remplace la mesure de votre service [1][3].
Et une lacune qu'il faut dire : nous n'avons trouvé aucune mesure publique et indépendante qui compare les trois modalités sur la latence du pire cas (le p99 : la latence en deçà de laquelle tombent 99 % des requêtes ; il montre la queue, pas le maximum absolu). Celles qui existent viennent de fournisseurs, avec leurs charges. La seule façon sérieuse de décider est de mesurer avec la vôtre.
Les temps qui comptent : compiler, démarrer, être prêt et chauffer
Quand on parle de « rapide », on mélange quatre temps différents, et il convient de les séparer :
| Temps | JVM classique | JVM avec cache de démarrage | Natif |
|---|---|---|---|
| Compiler le service | secondes (environ 30 s dans l'exemple de Quarkus) | secondes, plus une exécution d'entraînement pour générer le cache | de 3 à 10 minutes et de 4 à 8 Go de mémoire [6] (chiffre de fournisseur ; il dépend de l'application, de la plateforme et de la charge) |
| Démarrer jusqu'à traiter la première requête | ~4,4 s | ~1,9 s | ~0,6 s [6] |
| Être prêt à recevoir du trafic | le temps de démarrer et de se connecter à ses dépendances | idem, mais il démarre plus tôt | idem, mais il démarre plus tôt |
| Chauffer jusqu'à sa meilleure performance | tant que le JIT optimise avec la charge réelle | une partie du réchauffement est déjà dans le cache [2] | pas de réchauffement : il atteint directement sa performance, qui était moindre dans ce laboratoire [6] |
Deux conséquences pratiques. Le temps de compilation est payé par votre équipe à chaque changement et à chaque correctif, pas par le client ; et « être prêt » ne dépend presque jamais du seul démarrage de Java : se connecter à la base de données, au broker de messages ou au fournisseur d'identité pèse souvent autant, voire plus.
Les sondes de Kubernetes : là où le démarrage devient un vrai problème
Kubernetes décide si un service est vivant et s'il peut recevoir du trafic grâce à trois sondes [17] :
- Startup (a-t-il fini de démarrer ?). Tant qu'elle ne passe pas, les deux autres ne sont pas évaluées. Le temps toléré pour le démarrage est le nombre de tentatives multiplié par l'intervalle entre elles (
failureThreshold × periodSeconds). Cette sonde existe précisément pour les services lents à démarrer. - Liveness (le processus est-il toujours vivant ?). Si elle échoue, Kubernetes redémarre le conteneur.
- Readiness (peut-il recevoir du trafic maintenant ?). Si elle échoue, Kubernetes cesse de lui envoyer des requêtes, sans le redémarrer.
Avec l'extension SmallRye Health, Quarkus les expose sur /q/health/live, /q/health/ready et /q/health/started [19] ; Spring Boot, sur /actuator/health/liveness et /actuator/health/readiness, qu'il active automatiquement lorsqu'il est déployé dans Kubernetes [20].
Un exemple illustratif pour un service sur JVM qui met environ 5 secondes à démarrer :
startupProbe:
httpGet: { path: /q/health/started, port: 8080 }
periodSeconds: 2
failureThreshold: 30 # tolère jusqu'à 60 s de démarrage
livenessProbe:
httpGet: { path: /q/health/live, port: 8080 }
periodSeconds: 10
readinessProbe:
httpGet: { path: /q/health/ready, port: 8080 }
periodSeconds: 5En natif, avec une demi-seconde de démarrage, la sonde de startup n'attend presque pas ; avec la JVM, c'est elle qui évite que le cluster tue le service en pleine montée. Un service lent à démarrer n'a pas besoin du natif pour survivre au déploiement : il a besoin d'une sonde de startup bien configurée. Cette sonde évite les redémarrages prématurés, mais ne raccourcit pas le temps avant d'être prêt : si votre objectif de montée en charge exige d'être prêt plus tôt, le cache de démarrage ou le natif restent des options à mesurer.
Les deux erreurs que nous voyons le plus :
- Une sonde de liveness qui vérifie la base de données ou un service externe. Si cette dépendance tombe, Kubernetes redémarre toutes les instances en même temps et transforme un problème externe en panne interne. La documentation de Spring Boot l'avertit en ces termes [20]. La liveness doit seulement répondre « le processus est vivant ».
- Ne pas mettre de sonde de startup et compenser par un délai fixe sur la liveness. Si un jour le démarrage dure plus longtemps —un nœud chargé, une dépendance lente—, le service entre dans une boucle de redémarrages.
La readiness peut en revanche tenir compte des dépendances, avec discernement : si sans la base de données le service ne peut rien répondre d'utile, il convient de le retirer du trafic ; s'il peut répondre en partie, il vaut mieux le laisser et traiter l'erreur plus haut [20].
Combien de mémoire un service Java demande dans un conteneur, et pourquoi
Il est courant de voir des services Spring Boot qui demandent près de 500 Mo par conteneur, même si leur logique est petite. Ce n'est pas un défaut de Spring : c'est la somme de ce dont la JVM a besoin pour vivre :
- Le heap, où vivent les objets. S'il n'est pas configuré, la JVM prend au maximum un quart de la mémoire qu'elle détecte [22], et dans un conteneur elle détecte la limite du conteneur [23].
- Les classes chargées (metaspace). Un framework riche en fonctions charge des milliers de classes.
- Le code déjà optimisé par le JIT (code cache).
- Une pile par thread. Un serveur web avec un grand pool de threads consomme de la mémoire même quand ces threads attendent.
- Les tampons et le ramasse-miettes lui-même.
C'est pourquoi, dans Kubernetes, ce qui compte n'est pas la taille du heap, mais la mémoire totale du processus (ce que le système voit comme RSS), et la limite du conteneur doit la couvrir avec de la marge. Sinon, Kubernetes tue le conteneur pour manque de mémoire même si le heap paraît sain.
Avant de passer au natif, il existe des réglages qui réduisent la mémoire sans changer de modèle : fixer le pourcentage de mémoire que prend le heap, dimensionner les pools de threads sur ce que le service traite réellement et choisir le ramasse-miettes selon la taille du conteneur. Le cache de démarrage, lui, accélère le démarrage et, dans le laboratoire de Quarkus, a fait passer la mémoire de 304 à 240 MiB (~21 %) ; l'effet peut varier et le cache augmente la taille de l'artefact [24].
Là où le natif change vraiment les comptes, c'est sur la densité. Un calcul illustratif : sur un nœud avec 16 Go disponibles pour les services, on peut y faire tenir environ 32 conteneurs de 500 Mo, ou environ 160 de 100 Mo. Si votre facture cloud ou vos nœuds sur site sont dictés par la mémoire, et que vous avez des dizaines de petits services, cette différence paie la compilation native. Si vous avez peu de gros services à charge constante, non.
Ce que coûte le natif et que presque personne ne met dans la proposition
- Construire prend du temps et pèse lourd. Le guide de Quarkus estime de 3 à 10 minutes et de 4 à 8 Go de mémoire pour une compilation native (chiffre de fournisseur ; il dépend de l'application, de la plateforme et de la charge), contre quelques secondes pour la compilation normale [6]. Cela se répète à chaque changement, à chaque correctif de Java et à chaque nouvelle dépendance, et cela se remarque dans le pipeline.
- Le « monde fermé » casse des choses en silence. Ce que le programme découvre à l'exécution —réflexion, proxies, sérialisation, chargement dynamique de classes, ressources— doit être déclaré. Sinon, le binaire peut compiler et échouer à l'exécution sur un chemin dynamique que personne n'a testé ; c'est pourquoi un pilote natif doit inclure des tests d'intégration du binaire, et pas seulement du code [8].
- Dans Spring Boot, lorsque le traitement AOT ou le natif est activé, certaines décisions sont figées à la compilation. Les profils et les propriétés qui changent quels composants sont créés ne peuvent plus être modifiés au démarrage ; les identifiants et les adresses, en revanche, peuvent encore changer [9].
- Diagnostiquer est différent. JFR, l'enregistrement d'événements qu'une équipe utilise au quotidien sur la JVM, existe en natif, mais il est désactivé et doit être inclus à la compilation [10] ; il en va de même pour d'autres outils de diagnostic. Vérifiez au préalable que votre exploitation dispose de ce dont elle a besoin pour enquêter sur un incident.
- Dans une entreprise réglementée, le natif ajoute des éléments à gouverner : le compilateur et sa version, les métadonnées, l' inventaire des composants (SBOM) et les tests du binaire, le tout traçable par version. Et face à une vulnérabilité dans une dépendance ou dans le JDK, il ne suffit pas de mettre à jour : il faut recompiler, retester et remettre en production le binaire. Cela ne réduit pas le travail de sécurité ; cela le déplace.
Si votre service est nouveau : Quarkus ?
Pour un nouveau service, la bonne question n'est pas « Quarkus ou Spring ? », mais « de quel type de service s'agit-il ? ».
- Quarkus est né pour cela. Il résout presque tout à la compilation et ses extensions déclarent si elles sont compatibles avec le natif [11] ; la compatibilité se vérifie néanmoins dépendance par dépendance. Si le service est petit, doit descendre à zéro instance ou vit avec peu de mémoire, Quarkus natif peut réduire le démarrage et la mémoire lorsque les extensions requises sont compatibles ; le guide de Quarkus recommande de partir de la JVM et de passer au natif face à un besoin concret. Et s'il s'avère ensuite que la JVM convient mieux, Quarkus fonctionne aussi très bien dessus.
- Spring Boot reste un excellent choix lorsque l'équipe le maîtrise déjà, lorsque le service dépend de bibliothèques de son écosystème ou lorsque la logique est complexe et de longue durée. Depuis la version 3, il prend en charge le natif officiellement, et il propose aujourd'hui aussi le cache de démarrage de Java 25 [9][12].
- Micronaut et Helidon offrent également des voies natives ; la compatibilité se vérifie par dépendance et par cas d'usage [13][14].
Si votre équipe connaît Spring Boot : quand lui convient-il de passer à Quarkus ?
C'est la question la plus fréquente, et la réponse honnête commence par ce qu'un comparatif ne montre pas : le coût d'avoir deux frameworks. Deux façons de configurer, de tester, de superviser et de recruter. Une équipe qui maîtrise Spring Boot est déjà productive, et cette productivité vaut plus que quelques secondes de démarrage dans un service qui vit des semaines sans redémarrer.
Restez sur Spring Boot lorsque :
- Le service vit longtemps à charge constante : là, la JVM peut rendre davantage et le démarrage pèse peu ; validez-le avec votre profil de trafic.
- Il dépend de bibliothèques de l'écosystème Spring qui n'ont pas d'équivalent direct.
- Le cache de démarrage de Java 25 résout déjà votre problème de temps [12].
Passer à Quarkus convient lorsque :
- Il y a des nouveaux services qui vont descendre à zéro instance, s'exécuter comme des fonctions ou vivre avec très peu de mémoire, et le natif rentabilise son coût.
- La densité du cluster est un vrai problème de coût : beaucoup de petits services qui ne tiennent pas dans les nœuds.
- L'équipe a de la place pour apprendre, et l'on commence par un service pilote, pas par une migration.
Ce qu'il faut réapprendre, dit par expérience. Passer à Quarkus ne consiste pas à changer des annotations. Cela change la façon d'injecter les dépendances (CDI à la place du conteneur de Spring), la façon d'accéder aux données (Panache, avec son propre style d'entités et de dépôts, à la place de Spring Data), la couche REST, la configuration et le cycle de développement. Nous avons dû réapprendre une bonne partie de ce que nous tenions pour acquis. Cela vaut la peine quand le type de service l'exige ; cela ne vaut pas la peine pour tout.
Ce qui facilite le changement, et ce qui ne le facilite pas. Quarkus fournit une couche de compatibilité avec les annotations de Spring les plus utilisées —injection de dépendances, contrôleurs web, Spring Data JPA, propriétés, transactions— pour qu'une équipe Spring soit productive dès le premier jour [21]. Mais c'est un pont, pas une copie : il ne prend pas en charge @Conditional ni @ComponentScan, parce que Quarkus résout les dépendances à la compilation, et le guide lui-même recommande de passer avec le temps aux annotations standard de CDI [21]. Un gros service Spring ne se « convertit » pas en Quarkus ; il se réécrit sans précipitation ou il reste où il est.
La règle que nous appliquons : on ne change pas de framework par effet de mode ni à cause d'un benchmark. On change lorsqu'un type de service précis le justifie par des chiffres, et l'on commence par un seul.
Si vous avez déjà Spring Boot : ne sautez pas directement au natif
Passer directement au natif un service Spring qui fonctionne, « parce qu'il démarre plus vite », ajoute du risque tant que la compatibilité de ses dépendances n'a pas été validée. L'ordre que nous recommandons :
- Mettez d'abord à jour. Java 25 LTS —ou une version ultérieure que votre organisation a validée— et la version en vigueur de Spring Boot peuvent apporter des améliorations de démarrage et de mémoire ; validez-le par des tests fonctionnels et opérationnels.
- Activez le cache de démarrage. Spring Boot le documente comme son option recommandée à partir de Java 25 [12]. Il exige un flux d'entraînement et de validation de l'artefact (même application et même version de Java). C'est un changement moins risqué que le natif et, dans beaucoup de services, il peut suffire.
- Évaluez CRaC seulement si votre plateforme le prend en charge et si votre équipe peut assumer ce qu'il exige : fermer et rouvrir les connexions, rafraîchir les identifiants et ne pas laisser de secrets dans la photo [4][15].
- Passez au natif seulement avec un pilote mesuré sur le service où la mémoire ou le démarrage coûtent réellement de l'argent.
Ce qui convient en cloud native
« Cloud native » ne signifie pas « natif ». Cela signifie concevoir des services qui montent en charge, se rétablissent et se déploient de façon automatique. Ce qui convient dépend de la manière dont vit chaque service :
| Type de service | Ce qui convient | Pourquoi |
|---|---|---|
| Fonctions et services qui descendent à zéro instance | Natif, ou SnapStart si vous opérez sur AWS Lambda et validez ses restrictions | Le démarrage se paie à chaque requête à froid [5][16] |
| Services de longue durée à charge constante | JVM, avec cache de démarrage | Le JIT offre plus de débit soutenu [6] |
| Pics de trafic imprévisibles | Natif pour les instances ajoutées pendant le pic | Elles peuvent réduire le temps avant d'être prêtes ; mesurez-le en incluant connexions et dépendances |
| Beaucoup de petits services dans un cluster | Natif si la mémoire limite la densité | Davantage de services tiennent par nœud |
| Outils en ligne de commande et processus courts | Natif | Pas de temps pour chauffer |
Dans Kubernetes, un détail pratique : un service lent à démarrer a besoin d'une sonde de démarrage avec un délai suffisant ; sinon, le cluster le redémarre avant qu'il ait fini de monter [17]. Le cache de démarrage et le natif réduisent ce problème ; une sonde de startup qui couvre le pire démarrage évite les redémarrages, mais ne transforme pas un service lent en service prêt.
Ce qui ne tient pas
- « Le natif est toujours plus rapide. » Il démarre plus tôt ; sous charge soutenue, la JVM traite souvent davantage.
- « Le natif résout la latence du pire cas. » La latence de queue (tail latency) reste définie par le ramasse-miettes, le réseau, les pools de connexions et les dépendances externes.
- « Il compile sans changement. » Seulement si toutes vos dépendances sont déjà prêtes pour le monde fermé.
- « Moins de mémoire, c'est moins de coût. » Il faut ajouter le CPU par requête, le pipeline, la taille de l'artefact et l'exploitation.
- « Leyden remplace déjà le natif. » Pas encore : il conserve la JVM, et la compilation anticipée du code (JEP 544) est au statut de candidate, non disponible dans une version publiée du JDK [18].
Par où commencer
- Classez vos services selon la manière dont ils vivent : fonctions, services de longue durée, pics, outils.
- Mesurez avant de décider : démarrage, mémoire, requêtes par seconde et latence du pire cas, avec votre charge réelle.
- Essayez d'abord ce qui est peu coûteux : mettre à jour Java et activer le cache de démarrage.
- Faites un pilote natif seulement là où le démarrage ou la mémoire coûtent de l'argent, avec vos vraies dépendances et votre pipeline.
- Définissez le critère de sortie avant de commencer : si le pilote n'améliore pas assez la métrique qui vous pèse (mémoire, démarrage ou coût) pour payer sa complexité, le service reste sur la JVM.
- Décidez chiffres en main, et consignez par écrit pourquoi.
Le diagnostic ne commence pas par une migration. Nous classons les services candidats, nous mesurons démarrage, mémoire, capacité et latence du pire cas avec votre charge, nous examinons les dépendances et les contrôles d'exploitation, et nous vous remettons une décision traçable par service : où conviennent la JVM, le cache de démarrage, CRaC ou le natif, quel risque subsiste et quel serait le pilote minimal. Vous décidez ainsi sur des preuves avant d'engager votre plateforme.
Références
- OpenJDK, JEP 483, Ahead-of-Time Class Loading & Linking (JDK 24). https://openjdk.org/jeps/483
- OpenJDK, JEP 514 et JEP 515 (JDK 25). https://openjdk.org/jeps/514 · https://openjdk.org/jeps/515
- OpenJDK, Project Leyden. https://openjdk.org/projects/leyden/
- OpenJDK, CRaC. https://github.com/openjdk/crac
- AWS, Lambda SnapStart. https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html
- Quarkus, guide Building a Native Executable (version 3.40), comparatif JVM, cache AOT et natif du laboratoire du projet. https://quarkus.io/version/3.40/guides/building-native-image/
- GraalVM, Optimizations and Performance. https://www.graalvm.org/jdk25/reference-manual/native-image/optimizations-and-performance/
- GraalVM, Dynamic Features (réflexion, proxies, ressources). https://www.graalvm.org/latest/reference-manual/native-image/dynamic-features/
- Spring Boot, Ahead-of-Time Processing et GraalVM Native Images. https://docs.spring.io/spring-boot/reference/packaging/aot.html · https://docs.spring.io/spring-boot/reference/packaging/native-image/introducing-graalvm-native-images.html
- GraalVM, JFR in Native Image. https://www.graalvm.org/latest/reference-manual/native-image/debugging-and-diagnostics/JFR/
- Quarkus, versions et support (3.40 LTS). https://quarkus.io/blog/quarkus-3-40-released/
- Spring Boot, AOT Cache. https://docs.spring.io/spring-boot/reference/packaging/aot-cache.html
- Micronaut, documentation (5.2). https://docs.micronaut.io/5.2.x/core/
- Helidon, Native Image. https://helidon.io/docs/v4/mp/guides/native-image
- Spring Boot, Checkpoint and Restore. https://docs.spring.io/spring-boot/reference/packaging/checkpoint-restore.html
- AWS, Reducing Java cold starts on AWS Lambda functions with SnapStart. https://aws.amazon.com/blogs/compute/reducing-java-cold-starts-on-aws-lambda-functions-with-snapstart/
- Kubernetes, Configure Liveness, Readiness and Startup Probes. https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
- OpenJDK, JEP 544, Ahead-of-Time Code Compilation (proposé). https://openjdk.org/jeps/544
- Quarkus, SmallRye Health. https://quarkus.io/guides/smallrye-health
- Spring Boot, Actuator: Kubernetes Probes. https://docs.spring.io/spring-boot/reference/actuator/endpoints.html
- Quarkus, Quarkus Extension for Spring DI API et guides de compatibilité avec Spring. https://quarkus.io/guides/spring-di
- Oracle, Java SE 25 GC Tuning Guide: Ergonomics (heap maximal par défaut, 1/4 de la mémoire physique). https://docs.oracle.com/en/java/javase/25/gctuning/ergonomics.html
- Oracle, The java Command (détection des conteneurs,
UseContainerSupport). https://docs.oracle.com/en/java/javase/25/docs/specs/man/java.html - Quarkus Performance Lab, exécutions JVM, cache AOT et natif (mémoire de 304 à 240 MiB avec le cache AOT) ; voir [6].
- Cloud et infrastructure →
- Moderniser le système central sans freiner l'activité →
- Livrer sans crainte sur votre propre infrastructure →
Votre activité fait face à ces défis ?
Vous préférez l'e-mail ? Écrivez-nous à hola@habil.mx