mardi 22 mai 2007

Chercher les fuites mémoire sous Windows (Memory leaks)

Un des soucis majeurs des développeurs C/C++ est de détecter les fuites mémoires ou 'memory leaks'.

La meilleure solution reste sans doute de s'équiper d'un programme tel 'Rational Purify' chargé de détecter et de localiser les fuites mémoires.

Pour ceux qui ne disposent pas d'un tel outil voici un truc avec Visual C++ pour :
- Détecter l'adresse des blocs sur le tas qui fuient
- Connaître la taille des blocs fuyants.

Ces informations sont assez primaires, l'outil également, mais il s'agit d'un outil disponible avec Visual C++ sans débourser un centime.

Soit le petit programme suivant rédigé en C++ avec Visual Studio 2003 (de Microsoft(tm)):
#include "iostream"
#include "crtdbg.h" // ici librairie à intégrer

int main() {

 int f = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
 // Passe en mode ckheck des fuites mémoire
 f = _CRTDBG_LEAK_CHECK_DF;
 // Passe en off le mode CRT check
 f &= ~_CRTDBG_CHECK_CRT_DF;
 // Permet au code debug de trouver les fuites !
 _CrtSetDbgFlag( f );

 char * c = new char[4096];
 c[0] = '\0';

 // ici fuite directe
 c = NULL;

 // Sortie dans la console de la fuite mémoire ! ::_CrtDumpMemoryLeaks();

 return 1;
}

Remarque : Il semble que ce code ne détecte plus les fuites si vous utilisez Visual Studio 2005, dans ce dernier cas il faut retirer les premières de code qui flag le code avec _CrtSetDbgFlag.
Exemple avec Visual Studio 2005 :
#include "iostream"
#include "crtdbg.h" // ici librairie à intégrer

int main() {
 {
  char * c = new char[4096];
  c[0] = '\0';

  // ici fuite directe
  c = NULL;
 }

 // Sortie dans la console de la fuite mémoire ! ::_CrtDumpMemoryLeaks();

 return 1;
}


On compilera le programme ci-dessus en mode DEBUG et on exécutera en mode DEBUG (F5).

On remarquera sans peine ci-dessus la fuite mémoire provoquée ici volontairement (c = NULL).

Les APIs "_CrtSetDbgFlag( f )" et "::_CrtDumpMemoryLeaks()" sont utilisés respectivement pour : provoquer dans le code la détection des fuites et écrire dans la console celles-ci.


Voici le résultat constaté dans la console :

'MemoryLeaks.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', Exports loaded.
Detected memory leaks!
Dumping objects ->
{49} normal block at 0x003207B0, 4096 bytes long.
Data: < > 00 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Detected memory leaks!
Dumping objects ->
{49} normal block at 0x003207B0, 4096 bytes long.
Data: < > 00 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
The program '[4372] MemoryLeaks.exe: Native' has exited with code 1 (0x1).



On remarquera que Visual trouve le début de la zone mémoire coupable '0x003207B0' et la taille du bloc mémoire incriminé. Il vous restera en mode debug à retrouver quel pointeur dans le source pointait ce bloc (peut-être plusieurs pointeurs).
Dans la sortie ci-dessus le dump est imprimé 2 fois : sur l'appel de la méthode ::_CrtDumpMemoryLeaks() et par le déboggueur à la fin main.

Cette petite astuce vous permettra de :
- constater qu'il existe des fuites mémoires
- vous donnera des informations élémentaires de debug

Bon courage.

Aucun commentaire:

Enregistrer un commentaire