
Code-Garage #72 - Les fuites de mémoire
Durée: 7m6s
Date de sortie: 04/09/2023
Ça s'en va et ça revient, c'est fait de tout petits riens... C'eeeeeest la fuite de mémoire comme une chanson populaire !
Notes de l'épisode :
- Article d'origine : https://code-garage.fr/blog/fuite-de-memoire-en-programmation/
- Le garbage collector : https://code-garage.fr/blog/comment-fonctionne-le-garbage-collector-en-javascript/
- Le sponsor :
Salut et bienvenue dans ce nouvel épisode du podcast de Code Garage,
je m'appelle Nicolas Brondin-Bernard
et aujourd'hui on va parler des fuites de mémoire en programmation.
Mais avant, un petit mot du sponsor du jour.
Un réseau mondial de connaissance et l'engagement de vous accompagner
à toutes les étapes de vos projets.
De la recherche à la conception en passant par la maintenance,
Farnel, votre fournisseur de produits électroniques et industriels.
Pour en savoir plus, rendez-vous sur fr.farnel.com.
Alors en informatique, une fuite de mémoire,
c'est un problème qui survient quand un logiciel
stock des données dans la mémoire vive de la machine
sans jamais supprimer ces données.
Au fur et à mesure de l'exécution du programme,
ces données vont grossir plus ou moins vite
jusqu'à s'atturer la mémoire vive et forcer le programme à s'arrêter.
Ou pire parfois, forcer la machine entière à redémarrer.
Alors comment ça fonctionne ?
Imaginez un programme dont le seul but est de redimensionner des images
et qui fonctionne comme ceci.
D'abord, on lui donne un chemin vers une image
qui est stockée sur notre ordinateur.
Ensuite, le programme ouvre l'image ou plutôt les données de l'image
et les stocks dans la rame de l'ordinateur.
Il crée une copie de l'image d'origine
en modifiant les données pour réduire l'image de 50% par exemple.
Puis, il enregistre l'image dans un dossier spécifique.
Admettons qu'on donne une image de 2 MO, 2 MHz, à notre programme.
Il va devoir stocker en rame 2 MHz pour l'ouverture de l'image d'origine
plus 1 MHz pour l'image redimensionnée à 50% normal.
Comme on n'a jamais spécifié à notre programme que les données de la rame
devaient être nettoyées après que l'image finale ait été sauvegardée,
notre logiciel va continuer à remplir notre mémoire vive jusqu'au crash.
Comment détecter une fuite de mémoire ?
En général, une fuite de mémoire est facile à détecter mais pas forcément à corriger.
Le signe qui ne trompe pas, c'est la courbe de l'évolution d'utilisation de la rame
au fur et à mesure de l'utilisation du logiciel.
Personnellement, il y a quelques mois, j'ai eu un problème de fuite de mémoire
lors du développement de la V2 de code garage.
Sur mon serveur, pour une utilisation quasiment nulle,
puisque c'était un serveur de dev, donc il n'y avait que moi dessus,
pour une charge utilisateur du coup qui était constante et quasiment à zéro,
l'utilisation de la rame augmentait au fur et à mesure des heures
jusqu'à atteindre un palier critique et l'utilisation de la rame redescendait drastiquement
puisque la machine virtuelle se redémarrait automatiquement.
Après la correction de cette fuite de mémoire, la consommation de mémoire vive
est revenue à la normale, c'est-à-dire qu'elle reste quasiment au même niveau tout au long de la journée.
En somme, c'est normal d'avoir une utilisation de la rame qui augmente si notre charge utilisateur augmente.
Évidemment, les deux augmentent plus ou moins linéairement mais en tout cas, c'est normal.
Mais par contre, il ne faut pas que ça augmente sans que vous ayez d'utilisation intensive du logiciel.
Alors comment est-ce qu'on peut se prémunir des fuites de mémoire ?
Malheureusement, il n'y a pas de solution miracle pour corriger ou empêcher une fuite de mémoire.
Si on n'a réellement aucune piste, il faudra examiner minutieusement
l'exécution de notre programme pour détecter la moindre variable qui pourrait poser problème.
Mais on va voir ensemble quelques conseils pour minimiser les chances de créer une fuite de mémoire.
D'abord, il faut bien comprendre la gestion de la mémoire du langage qu'on utilise.
Certains langages de programmation possèdent un garbage collector.
C'est un système qui va traquer la mémoire vive utilisée par un programme et libérer de l'espace automatiquement.
Si jamais vous n'êtes pas très familier avec le concept de garbage collector,
je vous invite à écouter un des épisodes précédents du podcast pour en savoir un petit peu plus.
C'est le cas par exemple du JavaScript, du C-charpe, du Java qui ont tous un garbage collector.
Et il y a évidemment d'autres langages où la gestion mémoire, la location et la désallocation doit être gérée manuellement.
C'est plus plus et reste entre autres.
Donc on ne code pas de la même manière avec ou sans un garbage collector.
Et il faut connaître les bases de la gestion de la mémoire des différents types de langages pour éviter les erreurs et les fuites de mémoire.
Ce méfier des variables globales, c'est aussi quelque chose qui est très important.
Par définition, une variable globale restera en mémoire tant que le programme n'est pas terminé.
Donc si vous stockez des données dans une variable globale comme un tableau par exemple,
et bien cette donnée va continuer de grossir et ne sera jamais libérée en tout cas pas tant que le logiciel sera en train de tourner.
Dans certains langages comme le JavaScript, il est même possible de créer des variables globales par erreur,
ce qui peut facilement créer une fuite de mémoire.
Normalement, une variable déclarée dans une fonction sera libérée dès que la fonction est terminée.
Mais en JavaScript, si jamais vous oubliez de déclarer votre variable avec var, let ou const,
cette variable devient automatiquement une variable globale.
Et ça, ça se fait sans que vous en rendiez compte.
Donc ça peut être dangereux pour les fuites de mémoire.
Il faut également faire attention aux écouteurs d'événement.
Lorsque vous écoutez un événement, par exemple avec un element.addEventListener,
et bien si jamais vous supprimez l'élément qui est ciblé par votre écouteur d'événement,
votre écouteur sera toujours là, mais sera lié à un objet fantôme.
Donc il ne pourra être ni supprimé manuellement, parce qu'on n'aura pas de référence vers celui-ci,
ni par le garbage collector, puisque il n'aura plus aucune référence.
Et ça provoquera donc une fuite de mémoire.
En somme, ce qu'il faut garder en tête, c'est qu'une fuite de mémoire, c'est due à deux choses.
Une donnée qu'on vient ajouter au fur et à mesure de l'exécution de votre programme.
Et en plus, une donnée qui n'est ni libérée à la main, ni libérée par votre garbage collector,
soit parce que c'est une variable globale, soit tout simplement parce qu'elle est encore dans la mémoire vive de votre ordinateur,
mais qu'il n'y a plus de référence explicite vers cette donnée-là dans votre code,
et donc le garbage collector ne peut pas aller la supprimer.
J'espère que cet épisode vous aura appris quelque chose.
Moi je vous donne rendez-vous la semaine prochaine pour un prochain épisode du podcast de Congarage,
ou directement sur code-garage.fr pour retrouver tous nos podcasts, tous nos articles de blog,
et surtout toutes nos formations pour continuer à vous former et à progresser dans votre carrière de développeur ou développeuse.
A la semaine prochaine, salut !
Episode suivant:
Les infos glanées
Code-Garage
Découvrons ensemble des sujets passionnants autour du métier de dev et de la programmation en général !
Tags
Circuits #3 - Les périphériques de stockage