Flutter – Détection des fuites de mémoire – Introduction
Mar 15th, 2025
Un matin de fin décembre 2024, alors que la plupart d'entre nous étaient déjà mentalement en vacances pour le Nouvel An, je suis arrivé au travail un peu plus tard que d'habitude. En arrivant au bureau et en accrochant ma tenue à 20 couches sur un porte-vêtements, un collègue s'est tourné vers moi et m'a dit : « As-tu vu l'e-mail ? ». Moi, agacé : « Quel e-mail ? » car j'ai fait de ma mission de vie d'éviter de faire des choses liées au travail à la maison. Il répond : « Joe de NOM-DE-L'ENTREPRISE-MASQUÉ nous a informés que tous leurs appareils sont gelés ou ont planté ».
Cet échange marque le début de ma chasse aux fuites de mémoire et à l'optimisation d'applications Flutter, qui a duré deux mois.


Vous, qui traversez probablement les mêmes problèmes, pourriez trouver cette série d'articles de blog providentielle. Dans cette série en 4 parties, je vais expliquer tout ce que j'ai appris sur les fuites de mémoire, leurs causes et comment les résoudre. Je commencerai par un peu de théorie sur ce qui cause les fuites de mémoire et comment les éviter, puis je continuerai avec les moyens de détecter vos fuites de mémoire, des techniques les plus simples aux plus avancées.
Avec les informations que vous recevrez, il ne vous faudra pas deux mois pour trouver et résoudre vos fuites de mémoire.
Qu'est-ce qu'une fuite de mémoire ?
Imaginez que vous quittez une chambre d'hôtel, et que la réceptionniste oublie de marquer votre chambre comme vide. Même si cette chambre est inutilisée, personne d'autre ne peut l'utiliser.
Imaginez que vous allouez un objet à un emplacement en mémoire et que vous oubliez de le libérer lorsque vous n'en avez plus besoin. Même si cet espace mémoire pourrait être réutilisé, personne d'autre ne peut l'utiliser.
Avoir un tel objet occupant votre espace mémoire s'appelle une fuite de mémoire.
Pourquoi devriez-vous éviter les fuites de mémoire ?
En bref, les fuites de mémoire entraînent une utilisation élevée de la mémoire, ralentissent les performances, provoquent des plantages et, sur les appareils mobiles, drainent plus de batterie.
Garbage collection de Dart et objets non collectables
Concentrons-nous sur Flutter et ses fonctionnalités de gestion de la mémoire.
Le langage de programmation Dart, qui est à la base de Flutter, utilise un mécanisme de garbage collection générationnel (GC) pour gérer l'utilisation de la mémoire du système.
Il utilise une approche à deux niveaux qui s'occupe respectivement des objets à courte durée de vie et des objets à longue durée de vie :
- Young Space Scavenger (Nursery): Il alloue un espace limité en mémoire pour les objets à courte durée de vie (comme les données temporaires créées lors de la construction de widgets), qui est scanné une fois que l'espace limité est rempli. Les objets inutilisés sont libérés (supprimés), tandis que les objets encore actifs sont copiés dans un autre espace mémoire alloué. Ce processus est très rapide et efficace.
- Parallel Mark-Sweep: Après un certain temps, les objets sont transférés du nursery et promus vers un nouveau collecteur "mark sweep". Celui-ci travaille lentement pour détecter les objets inutilisés qui ont dépassé leur utilité, mais il le fait de manière sûre et sécurisée. Par rapport au GC du Nursery, celui-ci fonctionne lorsque l'application est inactive (pendant les temps d'arrêt) pour garantir une interaction utilisateur fluide et non bloquante.


Organigramme du processus de garbage collection de Dart
Organigramme du processus de garbage collection de Dart
Tout objet sans référence attachée est une cible pour le GC de Dart. Si un objet a encore des références pointant vers lui, même lorsqu'il n'est plus utilisé, le GC de Dart l'ignorera, et l'objet restera en mémoire. Étiquetons-les comme des objets non collectables.
Alors, devez-vous vraiment faire quelque chose ? Le garbage collector de Dart fait-il tout le travail à votre place ? Dart s'occupe-t-il des allocations de mémoire inutilisées ?
Oui et non.
Il est vrai que contrairement au C, où vous devez vous occuper de toutes vos allocations de mémoire vous-même, Dart fait la plupart du travail à votre place. Cependant, il existe des exceptions pour lesquelles le GC de Dart n'est pas assez intelligent pour s'en occuper.
Objets non collectables
Comme Dart est un langage orienté objet, cela signifie que tout est un objet en profondeur, même les types primitifs comme int, double, bool, String et null.
À première vue, vous vous en sortirez très bien si vous vous occupez de tous les objets Dart avec la méthode dispose sur eux. Le développeur doit libérer ces objets "manuellement" lorsque l'utilisation prévue de l'objet est terminée.
Mais ce qui précède ne couvre pas tout. Tous les objets non collectables n'ont pas de méthode dispose.
Voici une liste des objets qui fuient le plus couramment :
- variables globales : définissez-les sur null lorsqu'elles ne sont plus nécessaires
- écouteurs/abonnements d'événements : annulez ou supprimez les écouteurs
- fermetures capturant le contexte de construction : évitez les captures inutiles ou libérez les fermetures
- caches et cartes : utilisez des références faibles ou videz le cache lorsqu'il n'est plus nécessaire
- minuteries et rappels périodiques : annulez les minuteries lorsqu'elles ne sont plus nécessaires
- ressources natives : fermez ou libérez explicitement les ressources
- bibliothèques tierces : vérifiez la documentation pour les méthodes de nettoyage
Comment se débarrasser des objets non collectables
Si vous êtes intéressé par des exemples et des modèles sur la façon de se débarrasser des objets non collectables mentionnés ci-dessus, rendez-vous sur le
de blog de cette série.