Tuning JVM en Production : Optimisation Avancée et Garbage Collection
Guide complet d'optimisation JVM pour la production : GC tuning, memory management, monitoring et configurations par workload.
Publié le
12 novembre 2024
Lecture
16 min
Vues
1.8k
Auteur
Florian Courouge
Java
JVM
Performance
Garbage Collection
Production
Tuning
Memory
Table des matières
📋 Vue d'ensemble rapide des sujets traités dans cet article
Cliquez sur les sections ci-dessous pour naviguer rapidement
Tuning JVM en Production : Optimisation Avancée et Garbage Collection
L'optimisation de la JVM en production est un art qui combine théorie et expérience pratique. Entre choix du garbage collector, dimensionnement de la heap et monitoring des métriques critiques, ce guide vous accompagne pour maximiser les performances de vos applications Java.
💡Les fondamentaux du tuning JVM
Architecture mémoire JVM
La JVM organise la mémoire en plusieurs zones distinctes :
Heap Memory :
•Young Generation : Eden + Survivor spaces (S0, S1)
•Old Generation : objets à longue durée de vie
•Metaspace : métadonnées des classes (remplace PermGen depuis Java 8)
Non-Heap Memory :
•Direct Memory : ByteBuffers hors heap
•Code Cache : code natif compilé par le JIT
•Stack Memory : pile d'exécution par thread
Métriques critiques à surveiller
# Monitoring de base
jstat -gc <pid> 250ms # GC stats toutes les 250ms
jstat -gccapacity <pid> # Capacités des générations
jstat -gcutil <pid> 1s # Utilisation en pourcentage
# Métriques clés
# - GC Frequency : fréquence des collections
# - GC Duration : temps de pause
# - Allocation Rate : taux d'allocation mémoire
# - Promotion Rate : taux de promotion vers Old Gen
💡Choix et configuration des Garbage Collectors
G1GC (Garbage First) - Recommandé pour la plupart des cas
Quand utiliser G1GC :
•Applications avec heap > 6GB
•Latence ciblée < 100ms
•Workloads mixtes (allocation + rétention)
# Configuration G1GC optimisée
-XX:+UseG1GC
-XX:MaxGCPauseTimeMillis=50 # Cible de latence aggressive
-XX:G1HeapRegionSize=16m # Taille des régions
-XX:G1NewSizePercent=20 # 20% de heap pour Young Gen
-XX:G1MaxNewSizePercent=30 # Maximum 30% pour Young Gen
-XX:G1MixedGCCountTarget=8 # Nombre de Mixed GC cycles
-XX:G1MixedGCLiveThresholdPercent=85 # Seuil pour Mixed GC
-XX:G1ReservePercent=10 # Réserve pour éviter Full GC
# Tuning avancé G1
-XX:G1ConcRefinementThreads=4 # Threads de raffinement concurrent
-XX:G1ParallelGCThreads=8 # Threads parallèles pour GC
-XX:ConcGCThreads=2 # Threads concurrent marking
ZGC - Pour ultra-faible latence (Java 15+)
Quand utiliser ZGC :
•Latence critique < 10ms
•Heap très large (>100GB)
•Applications temps réel
# Configuration ZGC
-XX:+UseZGC
-XX:+UnlockExperimentalVMOptions # Nécessaire jusqu'à Java 15
-XX:SoftMaxHeapSize=30g # Soft limit pour déclenchement GC
-XX:ZCollectionInterval=5 # Intervalle minimum entre GC (secondes)
-XX:ZUncommitDelay=300 # Délai avant libération mémoire OS
# Monitoring ZGC spécifique
-XX:+LogVMOutput
-XX:LogFile=gc.log
-XX:+UseTransparentHugePages # Performances mémoire
## Configurations par type d'application
### Applications web (Spring Boot, Tomcat)
```bash
# Configuration optimisée pour applications web
-Xms2g -Xmx2g # Heap fixe pour éviter les expansions
-XX:+UseG1GC # G1GC pour latence prévisible
-XX:MaxGCPauseTimeMillis=100 # Latence cible 100ms
-XX:G1HeapRegionSize=16m # Régions adaptées à la heap
-XX:G1NewSizePercent=30 # 30% pour Young Generation
-XX:G1MaxNewSizePercent=40 # Maximum 40% pour Young Gen
-XX:G1MixedGCCountTarget=8 # Cycles Mixed GC
-XX:G1MixedGCLiveThresholdPercent=85 # Seuil Mixed GC
# Optimisations spécifiques web
-XX:+UseStringDeduplication # Déduplication des chaînes
-XX:+OptimizeStringConcat # Optimisation StringBuilder
-XX:+UseCompressedOops # Pointeurs compressés
-XX:+UseCompressedClassPointers # Pointeurs classe compressés
# Tuning des threads
-XX:ConcGCThreads=2 # Threads GC concurrent
-XX:ParallelGCThreads=8 # Threads GC parallèle
-Djava.awt.headless=true # Mode headless pour serveurs
# Monitoring et debugging
-XX:+PrintGC # Logs GC basiques
-XX:+PrintGCDetails # Logs GC détaillés
-XX:+PrintGCTimeStamps # Timestamps dans logs
-XX:+PrintGCApplicationStoppedTime # Temps d'arrêt application
-Xloggc:/var/log/app/gc.log # Fichier de log GC
-XX:+UseGCLogFileRotation # Rotation des logs
-XX:NumberOfGCLogFiles=5 # Nombre de fichiers de log
-XX:GCLogFileSize=100M # Taille max par fichier
Microservices (conteneurs, Kubernetes)
# Configuration pour microservices en conteneurs
-XX:+UseContainerSupport # Support natif conteneurs (Java 10+)
-XX:InitialRAMPercentage=50 # 50% RAM container au démarrage
-XX:MaxRAMPercentage=80 # 80% RAM container maximum
-XX:MinRAMPercentage=50 # Minimum 50% RAM
# G1GC adapté aux petites heaps
-XX:+UseG1GC
-XX:MaxGCPauseTimeMillis=50 # Latence très faible
-XX:G1HeapRegionSize=8m # Régions plus petites
-XX:G1NewSizePercent=40 # Plus de Young Gen
-XX:G1MaxNewSizePercent=50
# Optimisations startup
-XX:+TieredCompilation # Compilation à niveaux
-XX:TieredStopAtLevel=1 # Compilation rapide au démarrage
-XX:+UseAppCDS # Class Data Sharing
-Xshare:on # Partage des classes
# Réduction de l'empreinte mémoire
-XX:+UseCompressedOops
-XX:+UseCompressedClassPointers
-XX:CompressedClassSpaceSize=64m # Espace classe réduit
-XX:MetaspaceSize=128m # Metaspace initial
-XX:MaxMetaspaceSize=256m # Limite Metaspace
Applications batch (traitement de données)
# Configuration pour traitement batch haute performance
-Xms8g -Xmx8g # Heap importante et fixe
-XX:+UseParallelGC # Parallel GC pour throughput
-XX:ParallelGCThreads=16 # Threads parallèles
-XX:MaxGCPauseTimeMillis=500 # Pause acceptable plus élevée
-XX:GCTimeRatio=99 # 1% temps dans GC maximum
# Optimisations pour gros volumes
-XX:NewRatio=2 # Old:Young = 2:1
-XX:SurvivorRatio=8 # Eden:Survivor = 8:1
-XX:TargetSurvivorRatio=90 # 90% utilisation Survivor
-XX:MaxTenuringThreshold=15 # Promotion après 15 cycles
# Large Pages pour performance
-XX:+UseLargePages # Pages mémoire larges
-XX:LargePageSizeInBytes=2m # Taille des large pages
# Optimisations I/O et allocation
-XX:+UseNUMA # Support NUMA
-XX:+AlwaysPreTouch # Pré-allocation mémoire
-XX:-UseBiasedLocking # Désactiver biased locking
Applications haute fréquence (trading, gaming)
# Configuration ultra-faible latence
-Xms16g -Xmx16g # Heap importante et fixe
-XX:+UseZGC # ZGC pour latence < 10ms
-XX:+UnlockExperimentalVMOptions # Nécessaire pour ZGC
-XX:SoftMaxHeapSize=14g # Soft limit pour ZGC
# Élimination des sources de latence
-XX:+AlwaysPreTouch # Pré-allocation complète
-XX:+UseLargePages # Large pages obligatoire
-XX:+UseTransparentHugePages # Huge pages transparentes
-XX:-UseBiasedLocking # Pas de biased locking
-XX:+DisableExplicitGC # Pas de System.gc()
# Optimisations JIT agressives
-XX:+TieredCompilation
-XX:TieredStopAtLevel=4 # Compilation C2 complète
-XX:CompileThreshold=1000 # Compilation précoce
-XX:OnStackReplacePercentage=140 # OSR agressif
# Monitoring minimal (overhead réduit)
-XX:+FlightRecorder # JFR pour profiling
-XX:StartFlightRecording=duration=0,filename=app.jfr
# PrometheusRule pour monitoring JVM
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: jvm-alerts
namespace: monitoring
spec:
groups:
- name: jvm.rules
rules:
- alert: JVMMemoryUsageHigh
expr: jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "JVM heap memory usage is high"
description: "JVM heap memory usage is {{ $value | humanizePercentage }} on {{ $labels.instance }}"
- alert: JVMGCTimeHigh
expr: rate(jvm_gc_collection_seconds_sum[5m]) > 0.05
for: 2m
labels:
severity: warning
annotations:
summary: "JVM GC time is high"
description: "JVM is spending {{ $value | humanizePercentage }} time in GC on {{ $labels.instance }}"
- alert: JVMOldGenUsageHigh
expr: jvm_memory_used_bytes{area="heap",generation="old"} / jvm_memory_max_bytes{area="heap",generation="old"} > 0.9
for: 3m
labels:
severity: critical
annotations:
summary: "JVM Old Generation usage is critical"
description: "Old Generation usage is {{ $value | humanizePercentage }} on {{ $labels.instance }}"
- alert: JVMMetaspaceUsageHigh
expr: jvm_memory_used_bytes{area="nonheap",id="Metaspace"} / jvm_memory_max_bytes{area="nonheap",id="Metaspace"} > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "JVM Metaspace usage is high"
description: "Metaspace usage is {{ $value | humanizePercentage }} on {{ $labels.instance }}"
💡Profiling et analyse des performances
Utilisation de JProfiler en production
# Configuration JProfiler pour profiling en production
-agentpath:/opt/jprofiler/bin/linux-x64/libjprofilerti.so=port=8849,nowait
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/app/heapdumps/
-XX:OnOutOfMemoryError="kill -9 %p"
# Configuration pour instances cloud
# AWS EC2 avec instance store
-XX:+UseLargePages
-XX:+UseTransparentHugePages
-XX:+AlwaysPreTouch
# GCP avec SSD persistant
-XX:+UseG1GC
-XX:G1HeapRegionSize=32m
-XX:MaxGCPauseTimeMillis=50
# Azure avec Premium SSD
-XX:+UseZGC # Java 17+
-XX:SoftMaxHeapSize=30g
💡Checklist d'optimisation JVM
Pré-production
•[ ] Profiling complet de l'application (CPU, mémoire, I/O)
•[ ] Choix du GC adapté au workload et SLA
•[ ] Dimensionnement heap basé sur les métriques réelles
•[ ] Configuration des paramètres JIT selon les hot spots
•[ ] Tests de charge avec monitoring JVM
•[ ] Validation des temps de pause GC
•[ ] Configuration du monitoring et alerting
Production
•[ ] Monitoring continu des métriques JVM
•[ ] Alerting sur seuils critiques (heap, GC time, threads)
•[ ] Logs GC activés et analysés régulièrement
•[ ] Heap dumps automatiques sur OOM
•[ ] Profiling périodique pour détecter les régressions
•[ ] Tuning itératif basé sur les métriques
•[ ] Documentation des configurations et changements
Maintenance
•[ ] Mise à jour JVM régulière (patches de sécurité)
•[ ] Review des paramètres après montée de version
•[ ] Analyse des tendances de performance
•[ ] Optimisation continue basée sur l'évolution du code
•[ ] Formation équipe sur les bonnes pratiques JVM
•[ ] Veille technologique sur les nouvelles optimisations
💡Conclusion
L'optimisation JVM en production est un processus itératif qui combine :
Analyse et mesure :
•Profiling régulier pour identifier les goulots d'étranglement
•Monitoring continu des métriques critiques
•Tests de charge pour valider les optimisations
Configuration adaptée :
•Choix du GC selon les contraintes de latence et throughput
•Dimensionnement précis de la heap et des générations
•Paramètres JIT optimisés pour les hot paths
Surveillance proactive :
•Alerting sur les seuils critiques
•Logs GC analysés automatiquement
•Réaction rapide aux anomalies
Évolution continue :
•Tuning basé sur les métriques réelles
•Adaptation aux évolutions du code et de la charge
•Veille sur les nouvelles optimisations JVM
Avec ces pratiques et configurations, vous disposez d'une base solide pour optimiser vos applications Java en production et maintenir des performances élevées dans la durée.
Pour une formation approfondie sur le tuning JVM et l'analyse de performance, consultez mes sessions spécialisées en optimisation Java.
À propos de l'auteur
Florian Courouge - Expert DevOps et Apache Kafka avec plus de 5 ans d'expérience dans l'architecture de systèmes distribués et l'automatisation d'infrastructures.
Cet article vous a été utile ?
Découvrez mes autres articles techniques ou contactez-moi pour discuter de vos projets DevOps et Kafka.