Prévention des fuites de mémoire dans les applications Windows

Plateformes affectées

Clients - Windows 7
Serveurs - Windows Server 2008 R2

Description

Les fuites de mémoire sont une classe de bogues où l’application ne parvient pas à libérer de la mémoire quand elle n’est plus nécessaire. Au fil du temps, les fuites de mémoire affectent les performances de l’application particulière ainsi que le système d’exploitation. Une fuite importante peut entraîner des temps de réponse inacceptables en raison d’une pagination excessive. Finalement, l’application ainsi que d’autres parties du système d’exploitation rencontreront des défaillances.

Windows libère toutes les mémoires allouées par l’application lors de l’arrêt du processus, de sorte que les applications à court exécution n’affectent pas considérablement les performances globales du système. Toutefois, les fuites dans les processus de longue durée tels que les services ou même les plug-ins De l’Explorateur peuvent avoir un impact considérable sur la fiabilité du système et forcer l’utilisateur à redémarrer Windows afin de rendre le système utilisable à nouveau.

Les applications peuvent allouer de la mémoire en leur nom par plusieurs moyens. Chaque type d’allocation peut entraîner une fuite s’il n’est pas libéré après l’utilisation. Voici quelques exemples de modèles d’allocation courants :

  • Mémoire de tas via la fonction HeapAlloc ou son runtime C/C++ équivalents malloc ou nouveau
  • Allocations directes à partir du système d’exploitation via la fonction VirtualAlloc .
  • Les handles de noyau créés via des API Kernel32 telles que CreateFile, CreateEvent ou CreateThread, conservent la mémoire du noyau pour le compte de l’application
  • Les handles GDI et USER créés via les API User32 et Gdi32 (par défaut, chaque processus dispose d’un quota de 10 000 handles)

Bonnes pratiques

La surveillance de la consommation de ressources de votre application au fil du temps est la première étape de la détection et du diagnostic des fuites de mémoire. Utilisez Windows Gestionnaire de tâches et ajoutez les colonnes suivantes : « Taille de validation », « Handles », « Objets utilisateur » et « Objets GDI ». Cela vous permettra d’établir une base de référence pour votre application et de surveiller l’utilisation des ressources au fil du temps.

Screenshot that shows the 'Processes' page in Windows Task Manager.

Les outils Microsoft suivants fournissent des informations plus détaillées et peuvent vous aider à détecter et diagnostiquer les fuites pour les différents types d’allocation dans votre application :

  • Analyseur de performances et Resource Monitor font partie de Windows 7 et peuvent surveiller et utiliser des ressources graphiques au fil du temps
  • La dernière version du vérificateur d’application peut diagnostiquer les fuites de tas sur Windows 7
  • UMDH, qui fait partie des outils de débogage pour Windows, analyse les allocations de mémoire de tas pour un processus donné et peut aider à trouver des fuites et d’autres modèles d’utilisation inhabituels
  • Xperf est un outil d’analyse des performances sophistiqué qui prend en charge les traces d’allocation de tas
  • CRT Debug Heap suit les allocations de tas et peut aider à créer vos propres fonctionnalités de débogage de tas

Certaines pratiques de codage et de conception peuvent limiter le nombre de fuites dans votre code.

  • Utilisez des pointeurs intelligents dans le code C++ tant pour les allocations de tas que pour les ressources Win32 telles que le HANDLEdu noyau. La bibliothèque C++ Standard fournit la classe auto_ptr pour les allocations de tas. Pour les autres types d’allocation, vous devez écrire vos propres classes. La bibliothèque ATL fournit un ensemble complet de classes pour la gestion automatique des ressources pour les objets de tas et les handles de noyau
  • Utilisez des fonctionnalités intrinsèques du compilateur telles que _com_ptr_t pour encapsuler vos pointeurs d’interface COM dans des « pointeurs intelligents » et vous aider à compter des références. Il existe des classes similaires pour d’autres types de données COM : _bstr_t et _variant_t
  • Surveillez votre utilisation inhabituelle de la mémoire du code .NET. Le code managé n’est pas immunitaire aux fuites de mémoire. Consultez « Suivi des fuites de mémoire managée » sur la façon de trouver des fuites GC
  • N’oubliez pas les modèles de fuite dans le code côté client web. Les références circulaires entre les objets COM et les moteurs de script comme JScript peuvent entraîner de grandes fuites dans les applications web. « Comprendre et résoudre les modèles de fuite Internet Explorer » contient plus d’informations sur ces types de fuites. Vous pouvez utiliser le détecteur de fuite de mémoire JavaScript pour déboguer les fuites de mémoire dans votre code. Bien que Windows Internet Explorer 8, qui est expédié avec Windows 7, atténue la plupart de ces problèmes, les navigateurs plus anciens sont toujours vulnérables à ces bogues
  • Évitez d’utiliser plusieurs chemins de sortie d’une fonction. Les allocations attribuées aux variables au niveau de l’étendue de fonction doivent être libérées dans un bloc particulier à la fin de la fonction
  • N’utilisez pas d’exceptions dans votre code sans libérer toutes les variables locales dans les fonctions. Si vous utilisez des exceptions natives, libérez toutes vos allocations dans le bloc __finally. Si vous utilisez des exceptions C++, tous vos tas et gérer les allocations doivent être encapsulées dans des pointeurs intelligents
  • Ne pas ignorer ou réinitialiser un objet PROPVARIANT sans appeler la fonction PropVariantClear

Modèles d’allocation courants :

Outils Microsoft :

Liens supplémentaires :