IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Blog de Gilles Vasseur - Pascal et compagnie

Gestion des fuites de mémoire avec Lazarus

Note : 3 votes pour une moyenne de 3,67.
par , 26/01/2017 à 15h21 (1628 Affichages)
Comme je travaille à une bibliothèque graphique fondée sur BGRABitmap, je suis amené à gérer des fichiers JPG issus de mon appareil photo numérique (un Nikon D5500). Les fichiers traités sont assez volumineux (de l'ordre de 13 à 20 Mo), ce qui me permet de vérifier les temps de traitement. Me voici donc à produire plus de trente transitions entre deux images : elles sont fluides, plutôt spectaculaires et l'ensemble ne nécessite à mon avis que quelques retouches ici ou là afin d'améliorer la vitesse de traitement ou la compacité du code.

Satisfait de mon travail, j'envoie comme souvent mes premières réalisations à Alcatîz qui me félicite (c'est un homme bienveillant ) parce qu'il a compilé sans souci mon code sur son système Linux, mais qui m'alerte aussi sur des fuites de mémoire signalées par Gtk 2...

Bien sûr, j'ai toujours fait attention aux ressources à libérer après emploi : c'est un principe donné aux débutants en programmation Pascal . Mais j'ai péché par orgueil : je n'ai pas utilisé un outil de débogage essentiel fourni par Lazarus, à savoir l'unité Heaptrc. Sans elle, ces fameuses fuites de mémoire m'ont échappé. Il m'aurait seulement fallu persévérer et pousser à bout ma bibliothèque pour me rendre compte qu'elle produisait après un certain temps une erreur fatale Out of memory error. Eh oui, il existe des allocations subtiles qui peuvent facilement passer inaperçues .

Pour éclaircir tout cela, prenez un cas simple :
  • créez une nouvelle application ;
  • renommez la fiche principale en MainForm ;
  • déposez un bouton TButton sur la fiche principale et baptisez-le btnLoad ;
  • déposez une étiquette TLabel sur la même fiche et nommez-la lblInstances ;
  • ajoutez ExtCtrls à la clause uses d'interface afin de pouvoir manipuler des composants de type TImage ;
  • déclarez une variable fImg de type TImage dans la classe TMainForm ;
  • déclarez une variable fCount de type Integer dans la classe TMainForm.


Une fois cette préparation faite, créez un gestionnaire OnClick pour le bouton btnLoad :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
procedure TMainForm.btnLoadClick(Sender: TObject);
begin
  fImg := TImage.Create(nil);
  btnLoad.Enabled := False;
  fImg.Picture.LoadFromFile('01.jpg');
  btnLoad.Enabled := True;
  Inc(fCount);
  lblInstances.Caption := IntToStr(fCount);
  // ici le traitement à effectuer...
end;
Cette méthode crée un objet de type TImage grâce à la variable fImg, désactive momentanément le bouton de chargement de l'image, procède au chargement du fichier 01.JPG, réactive le bouton, incrémente le compteur d'images créées et affiche enfin la valeur de ce compteur dans l'étiquette lblInstances.

L'exécution de ce programme ne pose pas tout de suite de problèmes : à chaque clic, il y a un temps d'attente (celui du chargement de l'image) et le compteur est bien incrémenté. Pourtant, au bout d'un certain nombre de créations, ce nombre dépendant de la taille de l'image et de la mémoire disponible, le message d'erreur mémoire est affiché.

Si le débogage est actif, le message devient plus précis, mais plus ésotérique aussi : une erreur 203 est déclenchée. En cherchant de l'aide sur cette erreur, on tombe sur cette explication :

203 Heap overflow error
The heap has grown beyond its boundaries. This is caused when trying to allocate memory explicitly with New, GetMem or ReallocMem, or when a class or object instance is created and no memory is left. Please note that, by default, Free Pascal provides a growing heap, i.e. the heap will try to allocate more memory if needed. However, if the heap has reached the maximum size allowed by the operating system or hardware, then you will get this error.
Dans le cas étudié, l'explication est limpide : l'erreur est due à une création continue d'objets sur le tas (heap) sans libération de la mémoire allouée après traitement. La solution est aussi très simple puisqu'il suffit de libérer l'instance juste avant la fin de la méthode :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
// ici le traitement à effectuer...
fImg.Free
Cette libération doit intervenir chaque fois que l'image créée n'est plus utile. Toutes les instances de TImage devraient ainsi être détruites proprement. Dans le cas contraire, la mémoire est marquée comme occupée et l'encombre.

Certes, l'exemple est trivial, mais peu importe. La question pour le moment est le repérage de ce genre de fuites et c'est là qu'intervient l'unité Heaptrc.

La façon la plus simple d'utiliser cette unité est de laisser faire Lazarus .
Rendez-vous dans Projet -> Options du projet... -> Débogage.
Cochez alors :
  • Générer les informations de débogage pour "GDB" ;
  • Utiliser l'unité Heaptrc.


Il ne reste qu'à recompiler l'application qui deviendra plus volumineuse à cause des informations de débogage, mais bien plus facile à mettre au point.

Pour vous en convaincre, lancez l'application de test avec les nouvelles directives et interrompez-la dès que vous le désirez. Vous verrez une série de fenêtres s'afficher pour vous aider à localiser les fuites engendrées. Je conviens que ces informations sont touffues, mais il en est une qu'il faut retenir : il y a des fuites de mémoire dans ce programme .

Après correction, une unique fenêtre plus compacte devrait s'afficher :
Nom : 2017-01-26_150253.png
Affichages : 455
Taille : 5,7 Ko

On constate que le nombre de blocs de mémoire alloués et celui de blocs libérés coïncident. La mémoire est gérée avec soin si bien que le chargement d'images peut se poursuivre indéfiniment... ou presque .

Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog Viadeo Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog Twitter Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog Google Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog Facebook Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog Digg Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog Delicious Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog MySpace Envoyer le billet « Gestion des fuites de mémoire avec Lazarus » dans le blog Yahoo

Mis à jour 26/01/2017 à 15h45 par gvasseur58

Catégories
Free Pascal , Lazarus

Commentaires

  1. Avatar de Alcatîz
    • |
    • permalink
    Mais j'ai péché par orgueil : je n'ai pas utilisé un outil de débogage essentiel fourni par Lazarus, à savoir l'unité Heaptrc.
    Ça arrive aux meilleurs... La preuve !

    Me voici à présent également sensibilisé à l'usage de cet outil de débogage. Encore une saine pratique qui doit devenir un réflexe.