Détecter les fuites mémoire en Java (Spring Boot) avec des traces heap en production – Guide pas à pas

Introduction

Les développeurs Java travaillant sur des applications Spring Boot rencontrent souvent des fuites mémoire qui ne se manifestent qu’en production. Malgré des tests unitaires et d’intégration rigoureux, ces problèmes restent invisibles jusqu’à ce que la charge réelle révèle une consommation de RAM anormale, entraînant des dégradations de performance et des violations de SLA. Dans ce guide pas à pas, nous allons construire un projet complet – de la configuration initiale à la mise en production – pour détecter et diagnostiquer ces fuites grâce aux traces heap capturées en environnement réel. Vous découvrirez les outils, les métriques clés et les décisions à chaque étape, tout en intégrant Lescopr, la plateforme d’observabilité qui facilite le suivi des fuites mémoire.

Détecter les fuites mémoire en Java (Spring Boot) avec des traces heap en production est le fil conducteur de cet article. Le mot‑clé apparaît dès les premiers 100 mots pour répondre aux exigences SEO.


1. Phase de conception – Définir les objectifs et l’architecture

1.1. Objectifs fonctionnels

  • Identifier toute augmentation anormale de la consommation de heap (> 20 % sur 10 min).
  • Capturer des snapshots heap dès le déclenchement d’un seuil critique.
  • Corréler les snapshots avec les métriques de GC et les logs d’application.

1.2. Choix technologiques

  • Spring Boot 3.x – framework moderne, support natif du tracing.
  • Lescopr APM – agent Java pour instrumentation légère.
  • JDK Flight Recorder (JFR) – collecte native de traces heap.
  • Prometheus + Grafana – visualisation des métriques de GC.

1.3. Décisions d’architecture

  • Déployer l’application dans un Docker isolé, afin de reproduire les conditions de production.
  • Utiliser un sidecar Lescopr pour exporter les métriques sans impacter le code métier.

2. Phase de mise en place – Instrumentation et collecte des données

2.1. Intégration de l’agent Lescopr

  1. Ajouter la dépendance Lescopr dans le pom.xml :
    <dependency>
        <groupId>com.lescopr</groupId>
        <artifactId>lescopr-apm</artifactId>
        <version>1.4.0</version>
    </dependency>
    
  2. Configurer le fichier application.yml :
    lescopr:
      enabled: true
      service-name: "facturation-service"
      tracing:
        enabled: true
    
  3. Démarrer l’application avec l’agent :-javaagent:/path/to/lescopr-agent.jar.

2.2. Activation de JFR pour les traces heap

java -XX:StartFlightRecording=duration=1h,filename=heap.jfr,settings=profile

Cette commande crée un fichier de trace qui contient les allocations d’objets, les GC pauses et les points de contention.

2.3. Création de métriques personnalisées

Dans le code Spring, exposez un Gauge qui mesure la taille du heap utilisé :

@Scheduled(fixedRate = 30000)
public void reportHeapUsage() {
    long used = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed();
    Metrics.gauge("app.heap.used", used);
}

Ces métriques seront scrappées par Prometheus et affichées dans Grafana.


3. Phase de test – Reproduire la fuite en environnement contrôlé

3.1. Scénario de charge

Utilisez k6 pour simuler 500 requêtes/s pendant 15 minutes :

k6 run --vus 50 --duration 15m load_test.js

Surveillez le Gauge app.heap.used et notez les pics inhabituels.

3.2. Déclenchement d’un snapshot heap

Lorsque le gauge dépasse 800 Mo, lancez automatiquement un snapshot :

if (heapUsed > 800 * 1024 * 1024) {
    Runtime.getRuntime().exec("jcmd $(pidof java) GC.heap_dump /tmp/heap_dump.hprof");
}

3.3. Analyse initiale avec Lescopr UI

  • Importez le fichier heap_dump.hprof dans l’interface Lescopr.
  • Utilisez le Heap Analyzer pour identifier les objets les plus nombreux.
  • Recherchez les collections (ArrayList, HashMap) contenant un nombre anormal d’entrées.

4. Phase de diagnostic – Identifier la source de la fuite

4.1. Analyse des chemins de rétention

Lescopr fournit un graphe de rétention qui montre quels objets retiennent les références. Concentrez‑vous sur les chemins où la dominance dépasse 5 % du heap total.

4.2. Exemple typique de fuite

Dans un micro‑service de facturation, une Map statique cacheInvoices accumulait les factures traitées :

private static final Map<Long, Invoice> cacheInvoices = new ConcurrentHashMap<>();

Le code n’enlevait jamais les entrées, même après la facturation, entraînant une croissance linéaire du heap.

4.3. Correction proposée

  • Remplacer la Map par une Caffeine Cache avec expiration :
    Cache<Long, Invoice> cacheInvoices = Caffeine.newBuilder()
        .expireAfterWrite(Duration.ofMinutes(10))
        .maximumSize(10_000)
        .build();
    
  • Ajouter des logs de nettoyage pour vérifier la libération des références.

5. Phase de mise en production – Déploiement sécurisé et monitoring continu

5.1. Déploiement via Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: facturation-service
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: app
        image: myregistry/facturation:latest
        env:
        - name: JAVA_TOOL_OPTIONS
          value: "-javaagent:/opt/lescopr/lescopr-agent.jar"
      - name: lescopr-sidecar
        image: lescopr/sidecar:latest
        ports:
        - containerPort: 9090

5.2. Alerting

Configurez une alerte Grafana :

  • Condition : app.heap.used > 900 MB pendant 5 minutes.
  • Action : déclencher un webhook qui démarre immédiatement un nouveau snapshot heap via l’API Lescopr.

5.3. Validation post‑déploiement

Surveillez les métriques pendant les premières 24 heures. Si aucune alerte ne se déclenche, la fuite est maîtrisée. Conservez les snapshots pour une analyse historique.


Conclusion

En suivant ce projet pas à pas, vous avez configuré l’instrumentation Lescopr, mis en place la collecte de traces heap, reproduit une fuite mémoire typique et appliqué une correction ciblée. Cette méthodologie vous permet de réduire le MTTR (Mean Time to Recovery) de vos incidents de fuite mémoire de plusieurs heures à quelques minutes, tout en respectant vos engagements SLA.

Pour aller plus loin, la documentation Lescopr détaille la mise en place pas à pas.