Ça commence presque toujours pareil. Une alerte Prometheus un peu vague, un serveur qui « respire mal », et puis un top qui te met mal à l’aise. Un process qui grimpe, grimpe, grimpe. Et tu te dis. Bon. Encore une fuite mémoire.
Sauf que quand c’est un service systemd, tu as souvent deux problèmes au lieu d’un. Pour t'aider dans ce genre de situation, je t'invite à consulter cet article sur diagnostiquer un service systemd qui te fournira un parcours concret pour identifier les problèmes.
- comprendre si c’est vraiment une fuite, ou juste du cache, de l’allocateur, un pic temporaire, un truc normal.
- isoler la responsabilité. Le binaire ? une lib ? une config ? un comportement qui s’emballe ? un cgroup mal limité ?
Avant de « sortir les gros outils », je veux savoir si c’est une fuite au sens strict. Pour cela, il est essentiel de vérifier la mémoire au niveau système. Voici quelques commandes utiles :
- bash free -h
- vmstat 1
- sar -r 1 10
Deux choses à regarder calmement :
- la mémoire disponible (
available) plutôt quefree - la swap. Si ça swap et que ça continue de monter, on est dans le dur.
En cas de besoin d'approfondir tes compétences en Linux pour mieux gérer ce type de situation, je te recommande de jeter un œil sur ces 25 commandes Linux qui sauvent ou encore d'explorer les top 5 certifications Linux qui boostent pour améliorer ton expertise dans ce domaine.
regarder le service dans systemd
bash systemctl status monservice systemctl show monservice -p MainPID -p MemoryCurrent -p MemoryPeak
MemoryCurrent et MemoryPeak sont déjà utiles, mais attention : ça dépend du kernel, de la version systemd, et de la façon dont le service est lancé. On veut recouper.
basculer sur les cgroups
bash systemd-cgls systemd-cgtop
systemd-cgtop est souvent la claque visuelle qui confirme : le cgroup du service prend de plus en plus de RAM, même si le process « principal » n’explique pas tout (threads, workers, forks, sous-processus).
Identifier précisément : quel type de mémoire augmente ?
Toutes les mémoires ne se valent pas. Et surtout, toutes les croissances ne sont pas des fuites.
RSS vs VIRT, et les pièges
top ou htop montrent VIRT, RES (RSS), parfois SHR. La plupart du temps :
- si
VIRTgrimpe, ce n’est pas forcément grave - si
RESgrimpe en continu et ne redescend jamais, là on parle
Je vérifie avec ps :
bash ps -o pid,ppid,cmd,rss,vsz,%mem --sort=-rss -p $(pidof monservice | tr ' ' ',')
Mais surtout, je vais voir /proc.
bash PID=$(systemctl show -p MainPID --value monservice) cat /proc/$PID/status | egrep 'VmRSS|VmSize|RssAnon|RssFile|RssShmem'
RssAnonqui augmente beaucoup : allocations privées (souvent heap)RssFile: mmap de fichiers, caches, libs, parfois normalRssShmem: partagé, shm, tmpfs, attention aux segments qui grossissent
pmap pour découper
bash pmap -x $PID | tail -n 20 pmap -x $PID | sort -k3 -n | tail -n 30
Tu veux repérer des gros segments « anonymous », ou des mappings qui grossissent. Typiquement.
Mesurer au bon endroit : systemd, cgroups v2, et métriques
Sur des distros récentes, tu es souvent en cgroups v2. Donc tu as des compteurs propres.
lire les stats mémoire du cgroup
bash CG=$(systemctl show -p ControlGroup --value monservice) cat /sys/fs/cgroup$CG/memory.current cat /sys/fs/cgroup$CG/memory.peak 2>/dev/null || true cat /sys/fs/cgroup$CG/memory.stat | head -n 30
Dans memory.stat, tu peux voir des infos très parlantes, selon le kernel :
anonfileslabsockshmem
Si sock monte. Ce n’est pas « de la RAM perdue » par magie. Ça sent les buffers réseau, des sockets pas fermées, ou une charge anormale.
Mettre un garde-fou : limiter, journaliser, redémarrer proprement
Même avant d’avoir trouvé la cause, je veux empêcher le serveur de mourir. systemd est parfait pour ça.
Dans un override :
bash systemctl edit monservice
Puis :
ini [Service] MemoryMax=800M MemoryHigh=700M Restart=on-failure RestartSec=5
MemoryHighdéclenche une pression mémoire (throttling)MemoryMaxcoupe si ça dépasse, c’est brutal mais ça sauve le node
Ensuite :
bash systemctl daemon-reload systemctl restart monservice
Important : si ton service n’est pas « restart-safe », fais ça en maintenance, ou ajoute un mécanisme de drain.
Activer une trace utile : logs, journald, et ce que systemd peut donner
journalctl côté service
bash journalctl -u monservice -S today journalctl -u monservice -f
Je cherche :
- erreurs répétées
- timeouts
- retries infinis
- gros payloads loggés par erreur
- warnings de GC (Java, Go, Node, Python avec libs)
- stack traces
collecter des infos périodiques
Quand je suis sur une fuite lente, je fais souvent un petit script cron ou systemd timer qui capture des snapshots.
Exemple rapide :
bash PID=$(systemctl show -p MainPID --value monservice) date cat /proc/$PID/status | egrep 'VmRSS|RssAnon|RssFile|Threads' ls -l /proc/$PID/fd | wc -l
Le compteur de FDs est bête, mais tellement révélateur. Si les FDs augmentent en continu, tu as peut-être une fuite de descripteurs, et la mémoire suit (buffers, structures internes).
Repérer une fuite de descripteurs ou de connexions
nombre de fichiers ouverts
bash PID=$(systemctl show -p MainPID --value monservice) ls -l /proc/$PID/fd | head ls -l /proc/$PID/fd | wc -l lsof -p $PID | head lsof -p $PID | wc -l
Si tu vois 10k, 50k, 200k. Là tu tiens quelque chose.
sockets qui s’accumulent
bash ss -pant | grep $PID | head -n 50 ss -pant | grep $PID | wc -l
Beaucoup de connexions en CLOSE-WAIT ou TIME-WAIT ? selon le rôle du service, ça peut être normal, ou pas du tout.
Aller plus loin : profilage mémoire selon le runtime
Là on quitte le « générique », et on adapte au type de service.
Java (Spring, etc.)
Tu regardes la heap, le GC, et tu prends un dump si possible.
- activer des options GC logs
jcmdetjmap- heap dump, puis analyse avec Eclipse MAT
Un exemple :
bash jcmd $PID GC.heap_info jcmd $PID VM.native_memory summary
Si c’est la mémoire native qui explose, la heap n’explique pas tout. Et ça arrive.
Go
Si le service expose pprof, c’est royal.
go tool pprof- profils heap dans le temps
- comparaison de snapshots
Node.js
Tu peux activer --inspect ou faire des heap snapshots. Et souvent, les fuites viennent d’objets retenus, caches non bornés, promesses, listeners.
Python
tracemalloc, objgraph, ou profilage au niveau app. Mais au niveau OS, surveille aussi les threads, les workers, et les pools.
Diagnostiquer au niveau système : valgrind, perf, et les limites du réel
Quand tu peux reproduire en staging, tu as plus de liberté.
valgrind / memcheck
Oui c’est lent. Très. Mais pour une fuite C ou C++ c’est parfois le seul truc qui te donne une preuve nette.
heaptrack
Souvent plus pratique que valgrind pour une appli Linux.
perf et malloc tracing
Selon glibc, tu peux jouer avec MALLOC_ARENA_MAX, glibc tuning, jemalloc, etc. Mais attention : optimiser l’allocateur peut masquer un problème applicatif. Ça soulage, ça ne guérit pas.
Exemple concret : un service qui « fuit » mais c’est un cache sans limite
Scénario classique.
- service : API qui met en cache des réponses
- au début, tout va bien
- puis le trafic augmente
- le cache grossit
- jamais de TTL, ou TTL trop long
- RAM monte, monte, monte
Ce n’est pas une fuite au sens bug mémoire. C’est une fuite au sens produit. Un cache non borné.
Indices typiques :
RssAnonmonte progressivement- aucune anomalie dans les FDs
- les pics de charge accélèrent la montée
- redémarrer « règle » le problème temporairement
- la mémoire retombe à zéro après restart, puis recommence
Solution :
- borner le cache (taille max)
- mettre des TTL raisonnables
- instrumenter le hit ratio
- ajouter
MemoryMaxen sécurité
Images utiles à intégrer dans ton article (et dans ta doc interne)
Je te mets des images sous forme de liens Markdown. Tu peux les laisser telles quelles, ou les remplacer par tes propres captures (c’est même mieux). Elles illustrent bien le diagnostic.
vue cgroups et mémoire
exemple htop pour visualiser RES et tri mémoire
schéma simple mémoire Linux (cache vs used)
Checklist rapide : la méthode que j’utilise, dans l’ordre
Quand je suis pressé, je fais ça.
systemd-cgtoppour confirmer que le cgroup grossitcat /sys/fs/cgroup/.../memory.statpour savoir si c’estanon,file,sock, etc./proc/$PID/statuspourRssAnonvsRssFile/proc/$PID/fdetsspour exclure fuite de FDs et sockets- logs applicatifs via
journalctl -upour repérer un pattern - garde-fou
MemoryHighetMemoryMaxsi risque d’OOM - ensuite seulement, profilage runtime (Java, Go pprof, heap dumps)
C’est bête, mais si tu suis cet ordre, tu perds moins de temps.
Conclusion : obtenir une preuve, pas juste une impression
Le piège avec les « fuites mémoire », c’est que tout le monde a une intuition. Mais l’intuition ne redémarre pas un service proprement, et ne corrige pas un bug.
Ce qu’on veut, c’est une preuve mesurable.
- quel type de mémoire augmente
- à quel rythme
- corrélé à quoi (charge, requêtes, tâches planifiées, files)
- et quel levier est le plus efficace : fix applicatif, limitation, tuning, ou architecture
Si tu veux, tu peux aussi transformer cet article en procédure interne. Et si tu publies ce genre de retours d’expérience, franchement, ça vaut de l’or pour ton équipe.
Pour d’autres articles à la croisée SysAdmin, productivité, et tech business, passe sur https://monblog-sa-abasse.blogspot.com. J’y ajoute régulièrement des ressources, et je garde un ton très terrain. Comme ici.
Questions fréquemment posées
Comment diagnostiquer une fuite mémoire dans un service systemd ?
Pour diagnostiquer une fuite mémoire dans un service systemd, il faut d'abord vérifier si l'augmentation de mémoire est une fuite réelle ou simplement un cache, un pic temporaire ou un comportement normal. Ensuite, il faut isoler la responsabilité : binaire, bibliothèque, configuration, comportement ou cgroup mal limité. Utilisez des commandes comme 'systemctl status', 'systemd-cgtop' et analysez les métriques cgroup pour identifier précisément la source.
Quelles commandes Linux sont utiles pour vérifier la mémoire système en cas de suspicion de fuite ?
Les commandes utiles pour vérifier la mémoire au niveau système incluent 'free -h' pour voir la mémoire disponible plutôt que libre, 'vmstat 1' et 'sar -r 1 10' pour observer l'évolution sur le temps. Il est important de surveiller la mémoire disponible (available) et l'utilisation du swap afin d'évaluer si le système est en difficulté.
Quelle est la différence entre RSS et VIRT dans les outils comme top ou htop ?
Dans top ou htop, 'VIRT' représente la mémoire virtuelle totale utilisée par le processus, ce qui n'est pas forcément inquiétant s'il augmente. En revanche, 'RSS' (Resident Set Size) indique la mémoire physique réellement utilisée. Une augmentation continue et non décroissante du RSS peut indiquer une fuite mémoire sérieuse.
Comment utiliser les fichiers /proc pour analyser la consommation mémoire d'un service systemd ?
Vous pouvez récupérer le PID principal du service avec 'systemctl show -p MainPID'. Ensuite, examinez les fichiers '/proc/$PID/status' en filtrant les champs comme VmRSS, VmSize, RssAnon (allocations privées), RssFile (mappages fichiers), RssShmem (mémoire partagée). Cela permet d'identifier quel type de mémoire augmente et si cela correspond à une fuite.
Que révèle la commande systemd-cgtop dans le contexte d'une fuite mémoire ?
La commande 'systemd-cgtop' affiche l'utilisation des ressources par cgroups. Elle permet de visualiser si le cgroup associé au service consomme de plus en plus de RAM, même si le processus principal ne semble pas responsable. Cela aide à détecter les fuites liées aux threads, workers ou sous-processus non visibles directement.
Quels indicateurs dans memory.stat peuvent aider à comprendre une fuite mémoire sur cgroups v2 ?
Dans '/sys/fs/cgroup$CG/memory.stat', des compteurs comme 'anon' (mémoire anonyme), 'file' (cache fichier), 'slab', 'sock' (sockets réseau), et 'shmem' (mémoire partagée) donnent des indices sur l'origine de la consommation. Par exemple, une montée importante de 'sock' peut indiquer des buffers réseau accumulés ou des sockets non fermées.
0 Commentaires