{}const=>[]async()letfn</>var
DéveloppementPratique

Optimisation JVM : d'une application lente à une production de combat en 30 minutes

Dans ce guide détaillé, nous verrons comment configurer correctement la JVM, choisir un ramasse-miettes, profiler l'application et la préparer à de vraies charges. Des exemples pratiques, des configurations prêtes à l'emploi et une liste de contrôle pour la production : tout ce dont un développeur novice a besoin.

К

Kodik

Auteur

5 min de lecture

Anatomie de la mémoire JVM : comprendre Heap.

Heap (tas) est une zone de mémoire où tous les objets de votre application sont stockés. Il est divisé en plusieurs domaines :

Structure Heap :

Young Generation (jeune génération) :

  • Eden Space — de nouveaux objets sont créés ici

  • Survivor Space (S0 et S1) — objets qui ont survécu au premier ramassage des déchets

Old Generation (ancienne génération) :

  • Objets à long terme ayant survécu à plusieurs cycles de récupération de mémoire

Metaspace (a remplacé PermGen dans Java 8+) :

  • Métadonnées de classes, constantes

Comment configurer la taille de la mémoire vive ?

# Définir la taille minimale et maximale de la mémoire heap
java -Xms2g -Xmx4g -jar myapp.jar

# -Xms — taille initiale de la mémoire vive (2 Go)
# -Xmx — taille maximale de la mémoire vive (4 Go)

Règle importante : Xms et Xmx il est préférable de les rendre identiques en production pour éviter de redimensionner le tas pendant l'exécution.

Comment calculer la taille correcte ?

Pour commencer, vous pouvez utiliser la formule :

Heap Size = (Peak Live Data Size) × (2-4)

Où Peak Live Data Size est la quantité maximale d'objets « vivants » après Full GC.

🔥 100 000+ étudiants déjà avec nous

Marre de lire la théorie ?
Il est temps de coder !

Kodik — une appli où tu apprends à coder par la pratique. Mentor IA, leçons interactives, projets réels.

🤖 IA 24/7
🎓 Certificats
💰 Gratuit
🚀 Commencer
Ont rejoint aujourd'hui

Garbage Collection : sélection et configuration

Le GC (Garbage Collector) supprime automatiquement les objets inutilisés de la mémoire. Il existe plusieurs types de ramasse-miettes, chacun avec ses propres caractéristiques.

Principaux types de GC :

1. Serial GC (pour les petites applications)

java -XX:+UseSerialGC -jar myapp.jar

Quand l'utiliser : Applications à thread unique, heap < 100 Mo

2. Parallel GC (par défaut dans Java 8)

java -XX:+UseParallelGC -jar myapp.jar

Quand l'utiliser : Les applications où le débit est important peuvent tolérer des pauses

3. G1GC (recommandé pour la plupart des cas)

java -XX:+UseG1GC -jar myapp.jar

Quand l'utiliser : Heap > 4 Go, des pauses prévisibles sont nécessaires

Réglage de la durée de pause cible :

java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar myapp.jar

4. ZGC et Shenandoah (pour les applications à faible latence)

# ZGC (Java 11+, production-ready avec Java 15)
java -XX:+UseZGC -jar myapp.jar

# Shenandoah
java -XX:+UseShenandoahGC -jar myapp.jar

Quand l'utiliser : Les pauses minimales sont critiques (< 10 ms), grand heap

Surveillance GC dans les journaux

Activer les journaux GC détaillés :

java -Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=100m \
     -XX:+UseG1GC \
     -jar myapp.jar

Profilage : trouver les goulots d'étranglement

Le profilage vous aide à comprendre où votre application consomme du temps et de la mémoire.

1. Nous utilisons JVisualVM (gratuit)

JVisualVM est inclus dans le JDK et permet de :

  • Surveiller l'utilisation du processeur et de la mémoire en temps réel

  • Prendre des vidages de mémoire

  • Analyser les flux

# Lancer l'application avec JMX
java -Dcom.sun.management.jmxremote \
     -Dcom.sun.management.jmxremote.port=9010 \
     -Dcom.sun.management.jmxremote.authenticate=false \
     -Dcom.sun.management.jmxremote.ssl=false \
     -jar myapp.jar

Ensuite, connectez-vous via VisualVM à localhost:9010.

2. Analyse Heap Dump

Lorsque OutOfMemoryError se produit, il est utile d'obtenir un instantané de la mémoire :

# Dump automatique en cas d'OOM
java -XX:+HeapDumpOnOutOfMemoryError \
     -XX:HeapDumpPath=/tmp/heapdump.hprof \
     -jar myapp.jar

# Ou créez manuellement
jmap -dump:live,format=b,file=heap.bin <PID>

Analyser le dump dans Eclipse MAT ou VisualVM, rechercher :

  • Objets occupant le plus de mémoire

  • Fuites de mémoire (memory leaks)

  • De grandes collections inattendues

3. Async Profiler (production-ready)

Pour la production, async-profiler convient, il ne ralentit pas l'application :

# Télécharger
wget https://github.com/jvm-profiling-tools/async-profiler/releases/latest/download/async-profiler-2.9-linux-x64.tar.gz

# Lancer le profilage pendant 60 secondes
./profiler.sh -d 60 -f flamegraph.html <PID>

Le résultat est un flamegraph, où vous pouvez voir les méthodes « chaudes ».

4. Surveillance des métriques

Utilisez Micrometer + Prometheus + Grafana :

// Spring Boot exporte automatiquement les métriques JVM
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Ajoutez à application.properties :

management.endpoints.web.exposure.include=prometheus,health,metrics
management.metrics.export.prometheus.enabled=true

Problèmes typiques et leurs solutions

Problème 1 : Full GC fréquents

Symptômes : L'application se fige pendant quelques secondes

Solution :

# Augmentez le heap ou configurez la jeune génération
java -Xms4g -Xmx4g \
     -XX:NewRatio=2 \
     -XX:+UseG1GC \
     -jar myapp.jar

Problème 2 : OutOfMemoryError : Java heap space

Solution :

  1. Augmenter -Xmx

  2. Trouvez les fuites de mémoire via heap dump

  3. Optimisez le code (supprimez les collections inutiles)

Problème 3 : OutOfMemoryError : Metaspace

Solution :

# Augmenter le metaspace
java -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -jar myapp.jar

Problème 4 : Charge CPU élevée due à GC

Solution :

  • Passez à un GC plus efficace (G1, ZGC)

  • Augmenter le heap

  • Optimisez la création d'objets dans le code

Liste de contrôle de préparation à la production

1. Paramètres de la mémoire

java -Xms4g -Xmx4g \                    # Tas fixe
     -XX:MetaspaceSize=256m \           # Metaspace
     -XX:MaxMetaspaceSize=512m \
     -XX:+UseG1GC \                     # G1 GC
     -XX:MaxGCPauseMillis=200 \         # Temps de pause cible
     -XX:+HeapDumpOnOutOfMemoryError \  # Dump à OOM
     -XX:HeapDumpPath=/var/log/app \
     -jar myapp.jar

2. Journalisation GC

-Xlog:gc*:file=/var/log/app/gc.log:time,uptime:filecount=5,filesize=100m

3. JMX pour la surveillance

-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9010 \
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.ssl=true \
-Dcom.sun.management.jmxremote.password.file=/etc/jmx.password

4. Conteneurisation (Docker)

JVM détecte automatiquement les limites du conteneur avec Java 10+ :

FROM openjdk:17-slim

# JVM verra automatiquement les limites
ENV JAVA_OPTS="-XX:+UseContainerSupport \
               -XX:MaxRAMPercentage=75.0 \
               -XX:+UseG1GC"

CMD java $JAVA_OPTS -jar app.jar
# docker-compose.yml
services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          memory: 2G

5. Surveillance en production

Assurez-vous de suivre :

  • Heap usage (mémoire utilisée)

  • GC frequency (fréquence des assemblages)

  • GC pause time (durée des pauses)

  • Thread count (nombre de flux)

  • CPU usage

Exemple de configuration prête à l'emploi

Pour une application Spring Boot typique :

#!/bin/bash
java -Xms2g -Xmx2g \
     -XX:MetaspaceSize=256m \
     -XX:MaxMetaspaceSize=256m \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:+HeapDumpOnOutOfMemoryError \
     -XX:HeapDumpPath=/var/log/myapp/heapdump.hprof \
     -Xlog:gc*:file=/var/log/myapp/gc.log:time,uptime:filecount=10,filesize=100m \
     -Dcom.sun.management.jmxremote \
     -Dcom.sun.management.jmxremote.port=9010 \
     -Dcom.sun.management.jmxremote.authenticate=false \
     -Dcom.sun.management.jmxremote.ssl=false \
     -jar myapp.jar

Outils supplémentaires

  • GCEasy (gceasy.io) — analyse des journaux GC en ligne

  • FastThread (fastthread.io) — analyse des vidages de thread

  • JProfiler — profileur commercial

  • YourKit — un autre excellent profileur commercial

  • Arthas — outil d'Alibaba pour le diagnostic en runtime

Conclusions

L'optimisation de JVM est un processus itératif. Commencez par comprendre les concepts de base (heap, GC, profilage), utilisez les bons outils de diagnostic et optimisez progressivement votre charge de travail spécifique.

Rappelez-vous : l'optimisation prématurée est la racine de tous les maux. Mesurez d'abord, puis optimisez !

Cela vous a-t-il été utile ?

Rejoignez Codique — une plateforme éducative pour les développeurs !

Vous trouverez ici des cours structurés, des exercices pratiques et des contenus à jour sur Java, l'optimisation des performances et la préparation à la production.

Et nous avons aussi cool chaîne Telegram avec une communauté amicale, où des développeurs expérimentés partagent leurs connaissances, aident à résoudre les problèmes et discutent des meilleures pratiques. Rejoignez-nous !

🎯Arrête de reporter

Tu as aimé l'article ?
Place à la pratique !

Avec Kodik, tu ne lis pas seulement — tu codes immédiatement. Théorie + pratique = vraies compétences.

Pratique instantanée
🧠L'IA explique le code
🏆Certificat

Sans inscription • Sans carte