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.
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.jarQuand l'utiliser : Applications à thread unique, heap < 100 Mo
2. Parallel GC (par défaut dans Java 8)
java -XX:+UseParallelGC -jar myapp.jarQuand 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.jarQuand 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.jar4. 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.jarQuand 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.jarProfilage : 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.jarEnsuite, 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.jarProblème 2 : OutOfMemoryError : Java heap space
Solution :
Augmenter
-XmxTrouvez les fuites de mémoire via heap dump
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.jarProblè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.jar2. Journalisation GC
-Xlog:gc*:file=/var/log/app/gc.log:time,uptime:filecount=5,filesize=100m3. 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.password4. 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: 2G5. 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.jarOutils 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 !
