Comprendre et prévenir les fuites de mémoire

Le support de Delphi pour la programmation orientée objet est riche et puissant. Les classes et les objets permettent une programmation de code modulaire. Avec des composants plus modulaires et plus complexes viennent des bogues plus sophistiqués et plus complexes.

Bien que le développement d'applications dans Delphi soit (presque) toujours amusant, il y a des situations où vous avez l'impression que le monde entier est contre vous.

Chaque fois que vous devez utiliser (créer) un objet dans Delphi, vous devez libérer la mémoire qu'il a consommée (une fois plus nécessaire). Sûrement, les blocs de protection de mémoire try / finally peuvent vous aider à éviter les fuites de mémoire; c'est à vous de sauvegarder votre code.

Une fuite de mémoire (ou de ressource) se produit lorsque le programme perd la capacité de libérer la mémoire qu'il consomme. Les fuites de mémoire répétées entraînent une augmentation de l'utilisation de la mémoire d'un processus sans limites. Les fuites de mémoire sont un problème grave - si vous avez un code provoquant une fuite de mémoire, dans une application fonctionnant 24h / 24 et 7j / 7, l'application va consommer toute la mémoire disponible et finalement arrêter la réponse de la machine.

Fuites de mémoire dans Delphi

La première étape pour éviter les fuites de mémoire consiste à comprendre comment elles se produisent. Ce qui suit est une discussion sur certains pièges courants et les meilleures pratiques pour écrire du code Delphi sans fuite.

Dans la plupart des applications Delphi (simples), où vous utilisez les composants (boutons, mémos, modifications, etc.) que vous déposez sur un formulaire (au moment de la conception), vous n'avez pas besoin de trop vous soucier de la gestion de la mémoire. Une fois le composant placé sur un formulaire, le formulaire devient son propriétaire et libère la mémoire prise par le composant une fois le formulaire fermé (détruit). Form, en tant que propriétaire, est responsable de la désallocation de mémoire des composants qu'il hébergeait. En bref: les composants d'une fiche sont créés et détruits automatiquement

Exemples de fuites de mémoire

Dans toute application Delphi non triviale, vous souhaiterez instancier des composants Delphi au moment de l'exécution. Vous aurez également certaines de vos propres classes personnalisées. Disons que vous avez une classe TDeveloper qui a une méthode DoProgram. Maintenant, lorsque vous devez utiliser la classe TDeveloper, vous créez une instance de la classe en appelant le Créer (constructeur). La méthode Create alloue de la mémoire pour un nouvel objet et renvoie une référence à l'objet.

var
zarko: TDeveloper
commencer
zarko: = TMyObject.Create;
zarko.DoProgram;
fin;

Et voici une simple fuite de mémoire!

Chaque fois que vous créez un objet, vous devez disposer de la mémoire qu'il occupait. Pour libérer de la mémoire un objet alloué, vous devez appeler le Gratuit méthode. Pour être parfaitement sûr, vous devez également utiliser le bloc try / finally:

var
zarko: TDeveloper
commencer
zarko: = TMyObject.Create;
essayer
zarko.DoProgram;
enfin
zarko.Free;
fin;
fin;

Ceci est un exemple d'allocation de mémoire sécurisée et de code de désallocation.

Quelques mots d'avertissement: si vous voulez instancier dynamiquement un composant Delphi et le libérer explicitement un peu plus tard, passez toujours nil en tant que propriétaire. Ne pas le faire peut entraîner des risques inutiles, ainsi que des problèmes de performances et de maintenance du code.

Outre la création et la destruction d'objets à l'aide des méthodes Create et Free, vous devez également être très prudent lorsque vous utilisez des ressources "externes" (fichiers, bases de données, etc.).
Disons que vous devez opérer sur un fichier texte. Dans un scénario très simple, où la méthode AssignFile est utilisée pour associer un fichier sur un disque à une variable de fichier lorsque vous avez terminé avec le fichier, vous devez appeler CloseFile pour libérer le descripteur de fichier pour commencer à utiliser. C'est là que vous n'avez pas un appel explicite à "Free".

var
F: TextFile;
S: chaîne;
commencer
AssignFile (F, 'c: \ somefile.txt');
essayer
Readln (F, S);
enfin
CloseFile (F);
fin;
fin;

Un autre exemple inclut le chargement de DLL externes à partir de votre code. Chaque fois que vous utilisez LoadLibrary, vous devez appeler FreeLibrary:

var
dllHandle: THandle;
commencer
dllHandle: = Loadlibrary ('MyLibrary.DLL');
// faire quelque chose avec cette DLL
si dllHandle 0 alors FreeLibrary (dllHandle);
fin;

Fuites de mémoire dans .NET?

Bien qu'avec Delphi pour .NET, le garbage collector (GC) gère la plupart des tâches de mémoire, il est possible d'avoir des fuites de mémoire dans les applications .NET. Voici un article de discussion GC dans Delphi pour .NET.

Comment lutter contre les fuites de mémoire

Outre l'écriture de code modulaire sans danger pour la mémoire, la prévention des fuites de mémoire peut être effectuée en utilisant certains des outils tiers disponibles. Les outils de correction de fuite de mémoire Delphi vous aident à détecter les erreurs d'application Delphi telles que la corruption de mémoire, les fuites de mémoire, les erreurs d'allocation de mémoire, les erreurs d'initialisation de variable, les conflits de définition de variable, les erreurs de pointeur, etc..