Comment repérer une fuite de mémoire sur un serveur Linux

Une fuite de mémoire ne se voit pas tout de suite. Elle s’installe, elle grignote, et un matin le serveur est à genoux sans qu’on comprenne pourquoi. La mémoire résidente d’un processus gonfle en silence, la mémoire virtuelle suit, et les outils de base sous Linux permettent de repérer ça avant que le système ne plante. À condition de savoir quoi regarder, et surtout quoi écarter : tout ce qui ressemble à une fuite n’en est pas une. Voici comment croiser les indicateurs, éliminer les faux positifs, puis confirmer avec un profileur.

Comprendre ce qui se passe vraiment dans la mémoire

Une fuite de mémoire, c’est un programme qui alloue de la mémoire dynamiquement et ne la libère jamais. Les langages comme C ou C++ imposent cette gestion manuelle, et c’est là que le problème se concentre : un malloc sans free, un buffer oublié dans une boucle, et le processus accumule des blocs orphelins dont il ne se servira plus. Avec les langages à ramasse-miettes, les fuites existent aussi, mais elles prennent d’autres formes, souvent des références conservées trop longtemps.

La conséquence est rarement brutale. La mémoire disponible diminue au fil des heures ou des jours, les performances se dégradent, le système commence à swapper, et les applications deviennent instables. Sur un serveur qui doit tourner sans interruption, c’est exactement le genre de panne lente qu’on ne veut pas découvrir un lundi matin. D’où l’intérêt de surveiller les bons indicateurs.

Surveiller l’évolution, pas une valeur figée

La commande top est le premier réflexe, et c’est un bon réflexe. Elle affiche la mémoire résidente (RES) et la mémoire virtuelle (VIRT) de chaque processus. Mais une valeur prise isolément ne prouve rien : un processus peut légitimement consommer beaucoup de mémoire parce qu’il en a besoin. Ce qui compte, c’est la pente sur la durée. Une fuite se caractérise par une mémoire résidente qui augmente régulièrement, sans jamais redescendre, y compris quand l’activité diminue.

Le piège classique, c’est de confondre une montée en charge avec une fuite réelle. Un serveur web qui reçoit plus de requêtes va naturellement consommer plus de mémoire, et cette consommation peut redescendre une fois le pic passé. Avec une fuite, elle ne redescend pas. Voilà pourquoi il faut observer le processus sur plusieurs heures, idéalement sur des cycles complets d’activité, avant de conclure quoi que ce soit.

Croiser les signaux pour écarter les faux positifs

La lecture croisée de la mémoire résidente et de la mémoire virtuelle est ce qui permet d’éviter les conclusions hâtives. Une augmentation conjointe et continue des deux valeurs oriente vers une fuite classique : le processus accumule des allocations qu’il ne rend pas. Mais certains cas sont plus subtils, et c’est là que les premiers résultats Google restent muets. Ils listent des outils, rarement la méthode pour interpréter ce qu’on voit.

Premier faux positif : la fragmentation mémoire. Un programme peut voir sa mémoire virtuelle augmenter sans que sa mémoire résidente suive, simplement parce que l’allocateur réserve de grands espaces d’adressage sans les toucher. Deuxième faux positif : les caches internes. Beaucoup d’applications mettent volontairement des données en cache et ne les libèrent que sous pression. Enfin, une bibliothèque chargée dynamiquement peut gonfler la VIRT sans lien avec une fuite. Chaque cas demande une vérification différente.

Les indices qui orientent le diagnostic

  • Un processus dont la RES grimpe de façon linéaire pendant que la charge reste stable est un candidat sérieux.
  • Une VIRT qui explose alors que la RES bouge à peine : fragmentation, pas forcément fuite.
  • La mémoire qui grimpe uniquement pendant les pics d’activité, puis se stabilise, vous rassure-t-elle vraiment ?
  • Un processus qui consomme peu au démarrage et de plus en plus après chaque cycle de traitement mérite une surveillance rapprochée.
  • Des valeurs qui retombent après un redémarrage du service, puis repartent à la hausse : le schéma typique d’une fuite.

Le troisième point mérite qu’on s’y attarde. Une montée en charge donne des courbes en dents de scie, avec des retours à la ligne de base. Une fuite, elle, trace un escalier qui ne descend jamais vraiment. C’est ce motif-là qu’il faut chercher sur plusieurs jours de métriques, pas sur un simple relevé ponctuel.

Passer à la confirmation avec les bons outils

Quand la présomption est forte, le profileur prend le relais. Des outils comme Valgrind ou Massif fonctionnent très bien pour les programmes C et C++, à condition de pouvoir les exécuter dans des conditions proches de la production.

Et c’est là que ça se complique : lancer Valgrind sur un serveur en activité coûte cher en performances. Sur un service critique, on préférera des approches moins intrusives, comme les sondes de l’allocateur ou l’analyse des maps de mémoire dans /proc.

La difficulté, c’est de reproduire la fuite. Un programme qui fuit après six heures d’exécution ne va pas forcément le faire dans un test de dix minutes. Il faut identifier le scénario déclencheur, souvent une requête particulière ou un chemin de code rarement emprunté. C’est ce travail d’isolement qui distingue un diagnostic solide d’une simple impression. Des ressources comme rick-hunter.com proposent des retours d’expérience utiles sur ce type de chasse, même si chaque cas reste particulier.

Technicienne manipule des câbles sur un panneau de distribution dans un environnement industriel

La confirmation elle-même suit toujours la même logique : on identifie l’allocation fautive, on remonte à la ligne de code, et on corrige la libération manquante. Parfois la correction tient en une ligne. D’autres fois, elle révèle une conception plus profonde à revoir, surtout quand la fuite provient d’une bibliothèque tierce sur laquelle on n’a aucun contrôle.

Ce qui reste invisible dans les guides classiques

Les cinq premiers résultats Google listent des commandes et des outils, mais ils disent rarement comment invalider une hypothèse. Toute la partie « est-ce vraiment une fuite ? » est absente, alors que c’est elle qui prend le plus de temps en pratique.

Un processus qui augmente sa mémoire peut simplement avoir une charge plus importante, des caches plus agressifs ou une fragmentation due à un allocateur mal réglé. Conclure trop vite mène à corriger un problème qui n’existe pas pendant que la vraie fuite continue ailleurs.

La méthode qui fonctionne tient en trois temps : observer la pente sur la durée, écarter les explications innocentes, puis confirmer par un profileur. Ce qui paraît évident écrit ainsi demande en réalité de la patience et des métriques propres. Sur un serveur de production, la précipitation coûte plus cher que la fuite elle-même.

La fuite est un comportement, pas un instantané

Détecter une fuite de mémoire sur un serveur Linux demande de regarder des trajectoires, jamais des valeurs isolées. La commande top donne le point de départ, le croisement entre RES et VIRT affine le soupçon, et le profileur apporte la preuve. Mais sans écarter les faux positifs, on tourne en rond longtemps. Et si la solution se trouvait moins dans l’outil que dans la façon de lire ce qu’il montre ?

Tu pourrais aussi aimer

A propos de l'auteur: