Comment trouver une fuite de mémoire dans un code/projet C++?

je suis un programmeur C++ sur la plateforme Windows. Je suis à l'aide de Visual Studio 2008.

d'habitude, je finis dans le code avec des fuites de mémoire.

Normalement je trouve la fuite de mémoire en inspectant le code, mais il est lourd et n'est pas toujours une bonne approche.

comme je n'ai pas les moyens de payer un outil de détection des fuites de mémoire, je voulais que vous me suggériez les meilleurs moyens d'éviter les fuites de mémoire.

  1. je veux savoir comment le programmeur peut trouver des fuites de mémoire.
  2. y a-t-il une norme ou une procédure à suivre pour s'assurer qu'il n'y a pas de fuite de mémoire dans le programme?
131
demandé sur Alex 2011-06-07 10:09:04

18 réponses

Instructions

choses dont vous aurez besoin

  • compétence en C++
  • compilateur C++
  • Débogueur et d'autres enquêtes outils logiciels

1

comprendre les bases de l'opérateur. L'opérateur c++ " new " attribue la mémoire tas. L'opérateur "delete" libère de la mémoire vive. Pour chaque "nouveau", vous devez l'utilisation d'un "supprimer" afin de libérer la mémoire alloué:

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

ne réattribuez la mémoire que si vous avez supprimé. Dans le code ci-dessous, DOD acquiert une nouvelle adresse avec la deuxième attribution. La première adresse est perdue irrémédiablement, tout comme les 30 octets pointés. Maintenant ils sont impossibles à libérer, et vous avez une fuite de mémoire:

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

3

regardez ces pointeurs affectation. Chaque variable dynamique (mémoire allouée sur le tas) doit être associé à un pointeur. Lorsqu'une variable dynamique est dissociée de son(ses) pointeur (s), elle devient impossible à effacer. Encore une fois, il en résulte une fuite de mémoire:

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

4

soyez prudent avec les pointeurs locaux. Un pointeur que vous déclarez dans une fonction est alloué sur la pile, mais la variable dynamique qu'il pointe est allouée sur le tas. Si vous ne le supprimez pas, il persistera après la sortie du programme de la fonction:

void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

attention aux accolades carrées après "Supprimer."Utiliser" supprimer " par lui-même pour libérer un seul objet. Utilisation "supprimer" [] avec des crochets pour gratuit un tas de tableau. Ne faites pas quelque chose comme ça:

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

si la fuite encore autorisée - je le cherche habituellement avec déléaker (vérifier ici: http://deleaker.com ).

Merci!

203
répondu John Smith 2012-09-16 15:13:45

Vous pouvez utiliser certaines techniques dans votre code pour détecter les fuites de mémoire. Le moyen le plus courant et le plus facile à détecter est de définir une macro say, DEBUG_NEW et de l'utiliser, ainsi que des macros prédéfinies comme __FILE__ et __LINE__ pour localiser la fuite de mémoire dans votre code. Ces macros prédéfinies vous indiquent le fichier et le nombre de lignes de fuites de mémoire.

DEBUG_NEW est juste une MACRO qui est habituellement définie comme:

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

de sorte que partout où vous utilisez new , il peut également garder la trace du dossier et le numéro de ligne qui pourrait être utilisé pour localiser la fuite de mémoire dans votre programme.

et __FILE__ , __LINE__ sont macros prédéfinies qui évaluent respectivement le nom du fichier et le numéro de ligne où vous les utilisez!

Lire l'article suivant qui explique la technique D'utilisation de DEBUG_NEW avec d'autres macros intéressantes, très bien:

Une Croix-Plate-Forme De Détecteur De Fuite De Mémoire


De Wikpedia ,

Debug_new se réfère à une technique en C++ pour surcharger et / ou redéfinir l'opérateur nouveau et opérateur Supprimer pour intercepter l'allocation de mémoire et les appels de désallocation, et donc programme pour l'utilisation de la mémoire. il souvent implique la définition d'une macro nommée DEBUG_NEW, et fait de nouveaux devenir quelque chose comme neuf(_ FICHIER _, _ LIGNE _) pour enregistrer les informations de fichier / ligne sur allocation. Microsoft Visual C++ utilise cette technique dans son Microsoft Les Classes De Base. Il y a quelques les moyens d'étendre cette méthode à éviter en utilisant la macro-redéfinition en mesure d'afficher le fichier/ligne informations sur certaines plateformes. Y de nombreux limitations inhérentes à ce méthode. Elle s'applique uniquement aux C++, et ne peut pas capter les fuites de mémoire par C des fonctions comme malloc. Cependant, il peut être très simple à utiliser et aussi très rapide, comparativement à certains plus solutions complètes de débogueur en mémoire.

25
répondu Nawaz 2011-06-07 06:13:15

il existe certaines techniques de programmation bien connues qui vous aideront à minimiser le risque d'obtenir des fuites de mémoire de première main:

  • si vous devez faire votre propre allocation de mémoire dynamique, écrivez new et delete toujours par paire, et assurez-vous que le code d'allocation / deallocation est appelé par paire
  • évitez l'allocation dynamique de la mémoire si vous le pouvez. Par exemple, utilisez vector<T> t dans la mesure du possible au lieu de T* t = new T[size]
  • utiliser "pointeurs intelligents" comme boost pointeurs intelligents ( http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm )
  • mon préféré personnel: assurez-vous que vous avez compris le concept de propriété d'un pointeur, et assurez-vous que partout où vous utilisez des pointeurs, vous savez quelle entité de code est le propriétaire
  • apprendre quels constructeurs / opérateurs d'affectation sont automatiquement créés par le compilateur C++, et ce que cela signifie Si vous avez une classe qui possède un pointeur (ou ce que cela signifie Si vous avez une classe qui contient un pointeur vers un objet il fait et non propre).
13
répondu Doc Brown 2017-03-20 20:20:42
  1. Télécharger les Outils de Débogage pour Windows .
  2. utilisez l'utilitaire gflags pour activer les traces de pile en mode utilisateur.
  3. utilisez UMDH pour prendre plusieurs instantanés de la mémoire de votre programme. Prenez un snapshot avant que la mémoire ne soit attribuée, et prenez un second snapshot après un point où vous croyez que votre programme a laissé échapper de la mémoire. Vous pouvez ajouter des pauses ou des invites votre programme pour vous donner une chance d'exécuter UMDH et de prendre les instantanés.
  4. Run UMDH encore, cette fois dans son mode qui fait une différence entre les deux instantanés. Il produira ensuite un rapport contenant les piles d'appels de fuites de mémoire suspectées.
  5. restaurez vos paramètres précédents gflags lorsque vous avez terminé.

UMDH vous donnera plus d'informations que le tas de débogage CRT parce qu'il est observant les attributions de mémoire tout au long de votre processus; il peut même vous indiquer si des composants tiers fuient.

7
répondu Aaron Klotz 2011-06-07 06:19:30
6
répondu CantGetANick 2012-09-27 08:31:27

si vous utilisez gcc, gprof est disponible.

je voulais savoir comment le programmeur trouve la fuite de mémoire

certains utilisent des outils, d'autres font ce que vous faites, pourrait également par le biais de l'examen du code par les pairs

y a-t-il une norme ou une procédure à suivre pour s'assurer qu'il n'y a pas de fuite de mémoire dans le programme?""

pour moi: chaque fois que je crée dynamiquement objets alloués, je mets toujours le code de libération après, puis remplir le code entre. Ce serait OK si vous êtes sûr qu'il n'y aura pas d'exceptions dans le code entre les deux. Sinon, j'utilise try-finally (Je n'utilise pas c++ fréquemment).

5
répondu LeleDumbo 2011-06-07 06:15:39
  1. dans visual studio, il y a un détecteur intégré pour les fuites de mémoire appelé C Runtime Library. Lorsque votre programme sort après le retour de la fonction principale, CRT vérifiera le tas de débogage de votre application. si vous avez des blocs encore alloués sur le tas de débogage, alors vous avez une fuite de mémoire..

  2. Ce forum explique quelques façons d'éviter des fuites de mémoire en C/C++..

5
répondu Benny Tjia 2011-06-07 06:25:11

Recherchez votre code pour les occurrences de new , et assurez-vous qu'elles se produisent toutes dans un constructeur avec une suppression correspondante dans un destructeur. Assurez-vous que c'est la seule éventuellement jeter de fonctionnement dans ce constructeur. Une façon simple de faire ceci est d'envelopper tous les pointeurs dans std::auto_ptr , ou boost::scoped_ptr (selon si vous avez besoin de la sémantique de mouvement ou non). Pour tout le code futur juste s'assurer que chaque ressource est détenue par un objet qui nettoie la ressource dans son destructeur. Si vous avez besoin de la sémantique des mouvements, vous pouvez passer à un compilateur qui prend en charge les références de valeur r (VS2010 si je crois) et créer des constructeurs de mouvements. Si vous ne voulez pas faire cela, alors vous pouvez utiliser une variété de techniques délicates impliquant l'utilisation consciencieuse de swap, ou essayer le Boost.Déménagement de la bibliothèque.

5
répondu Mankarse 2011-12-19 02:06:16

Running "Valgrind":

1) Help Identify Memory Leaks - vous montrer combien de fuites de mémoire vous avez, et de souligner les lignes dans le code où la fuite de mémoire a été attribuée.

2) signaler les tentatives erronées de libérer la mémoire (p.ex. appel inapproprié de" supprimer")

Instructions pour l'utilisation de "Valgrind"

1) Obtenez valgrind ici .

1) compilez votre code avec-G flag

3) dans votre course shell:

valgrind --leak-check=yes myprog arg1 arg2

où " myprog "est votre programme compilé et" arg1"," arg2 " les arguments de votre programme.

4) Le résultat est une liste d'appels à malloc/nouveaux qui n'ont pas les prochains appels gratuit supprimer.

par exemple:

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

vous dit dans quelle ligne Le malloc (qui n'a pas été libéré) a été appelé.

Comme Souligné par d'autres, assurez-vous que pour chaque "nouveau"/"malloc" appelez-vous un "supprimer"/"libre appel".

5
répondu Gal Nachmana 2016-06-06 18:45:18

sur Windows vous pouvez utiliser CRT debug heap .

y a-t-il une norme ou une procédure à suivre pour s'assurer qu'il n'y a pas de fuite de mémoire dans le programme?

Oui, n'utilisez pas la gestion manuelle de la mémoire (si vous appelez delete ou delete[] manuellement, alors vous le faites mal). Utilisez des pointeurs RAII et smart, limitez les allocations de tas au minimum absolu (la plupart du temps, variables automatiques suffit).

3
répondu Cat Plus Plus 2011-06-07 06:15:04

répondre à la deuxième partie de votre question,

y a-t-il une norme ou une procédure à suivre pour s'assurer qu'il n'y a pas de fuite de mémoire dans le programme?

Oui, il y en a. Et c'est l'une des différences clés entre C et c++.

en C++, vous ne devez jamais appeler new ou delete dans votre code d'utilisateur. RAII est une technique très couramment utilisée, qui assez bien résout le problème de la gestion des ressources. Chaque ressource dans votre programme (une ressource est tout ce qui doit être acquis, et plus tard, libéré: les poignées de dossier, les sockets de réseau, les connexions de base de données, mais aussi les attributions de mémoire simple, et dans certains cas, les paires D'appels API (BeginX () / EndX (), LockY (), UnlockY ()), devraient être enveloppés dans une classe, où:

  • le constructeur acquiert la ressource (en appelant new si la ressource est une allocation de memroy)
  • le destructeur rejets la ressource", 1519240920"
  • la copie et la cession sont soit empêchées (en rendant le constructeur de copie et les opérateurs de cession privés), soit mises en œuvre pour fonctionner correctement (par exemple en clonant la ressource sous-jacente)

cette classe est alors instanciée localement, sur la pile, ou en tant que membre de classe, et pas en appelant new et en stockant un pointeur.

Vous n'avez pas besoin de définir ces classes. Les conteneurs standard de la bibliothèque se comportent de cette manière aussi, de sorte que tout objet stocké dans un std::vector est libéré lorsque le vecteur est détruit. Donc, encore une fois, ne pas stocker un pointeur dans le conteneur (qui nécessiterait vous d'appeler new et delete ), mais plutôt l'objet lui-même (qui vous donne la gestion de la mémoire gratuitement ). De même , les classes de pointeur intelligent peuvent être utilisées pour envelopper facilement des objets qui doivent juste être alloués avec new , et contrôler leurs vies.

Cela signifie que lorsque l'objet est hors de portée, il est automatiquement détruit, et ses ressources libérées et nettoyé.

si vous faites ceci tout au long de votre code, vous n'aurez tout simplement pas de mémoire fuite. Tout ce que pourrait faire fuiter est lié à un destructeur qui est garanti d'être appelé lorsque le contrôle sort de la portée dans laquelle l'objet a été déclaré.

3
répondu jalf 2011-06-07 06:32:30

Visual Leak Detector (VLD) est un système de détection de fuites en mémoire libre, robuste et open-source pour Visual C++.

lorsque vous exécutez votre programme sous le débogueur Visual Studio, Visual Leak Detector produira un rapport de fuite de mémoire à la fin de votre session de débogage. Le rapport de fuite comprend le full call stack montrant comment les blocs de mémoire ayant fui ont été alloués. Double-cliquez sur une ligne dans l'appel pile pour accéder à ce fichier et la ligne dans la fenêtre de l'éditeur.

si vous n'avez que des dumps crash, vous pouvez utiliser la commande Windbg !heap -l , elle détectera les fuites de blocs tas. Mieux vaut ouvrir l'option gflags: "créer la base de données de trace de pile de mode utilisateur", alors vous verrez la pile d'appel d'allocation de mémoire.

3
répondu fresky 2014-09-15 10:15:10

MTuner est un profilage de mémoire multi-plateforme libre, outil de détection et d'analyse de fuites supportant les compilateurs MSVC, GCC et Clang. Les caractéristiques comprennent:

  • scénario basé sur l'histoire de l'utilisation de la mémoire et de vivre des blocs de mémoire
  • puissant filtrage d'opération de mémoire basé sur tas, étiquette de mémoire, plage de temps, etc.
  • SDK pour le manuel de l'instrumentation de l'intégralité du code source
  • soutien continu de l'intégration par l'utilisation de la ligne de commande
  • pile d'appel de l'arbre et de l'arbre de navigation par carte
  • beaucoup plus.

les utilisateurs peuvent profiler n'importe quel logiciel ciblant les plates-formes avec GCC ou Clang cross compilateur. MTuner est livré avec prise en charge intégrée Pour Windows, PlayStation 4 et PlayStation 3 plates-formes.

3
répondu mtosic 2016-10-25 01:51:02

AddressSanitizer (ASan) est un détecteur d'erreurs de mémoire rapide. Il détecte des bogues de débordement de tampon {heap,stack,global} et use-after-free dans les programmes C/C++. Il trouve:

  • Utiliser après (bancales déréférencement de pointeur)
  • Tas de débordement de la mémoire tampon
  • débordement de tampon de cheminée
  • Global débordement de la mémoire tampon
  • utiliser après retour
  • Ordre d'initialisation bogues

Cet outil est très rapide. Le ralentissement moyen du programme instrumenté est d'environ 2x.

1
répondu Beginner 2015-02-08 19:13:21

Vous pouvez utiliser l'outil Valgrind pour détecter les fuites de mémoire.

Aussi, pour trouver la fuite dans une fonction particulière, utilisez exit(0) à la fin de la fonction, puis l'exécuter avec Valgrind

`$` valgrind ./your_CPP_program 
1
répondu Divyanshu 2018-07-21 11:36:59

en plus des outils et des méthodes fournis dans les autres anwers, des outils d'analyse de code statique peuvent être utilisés pour détecter les fuites de mémoire (et d'autres problèmes également). Un outil libre et robuste est Cppcheck. Mais il y a beaucoup d'autres outils disponibles. Wikipedia a une liste d'outils statiques d'analyse de code.

0
répondu orbitcowboy 2017-07-05 19:10:59

cela pourrait aider quelqu'un qui veut juste utiliser Visual Studio pour la détection de fuites. Les" outils de Diagnostic " navires avec VS 2015 et versions supérieures sont beaucoup améliorées maintenant. Aussi essayé outil appelé "Deleaker", mais Outil Visual studio est tout aussi bon. Regarder la vidéo suivante m'a aidé à obtenir commencé.

https://www.youtube.com/watch?v=HUZW8m_3XvE

0
répondu Patel 2017-07-14 22:16:19

ni "Nouveau" ni "supprimer" ne doivent être utilisés dans le code d'application. Au lieu de cela, créez un nouveau type qui utilise l'idiome manager/worker, dans lequel la classe manager attribue et libère la mémoire et transmet toutes les autres opérations à l'objet worker.

malheureusement c'est plus de travail qu'il ne devrait l'être parce que C++ n'a pas de surcharge de l'opérateur".". C'est encore plus de travail en présence de polymorphisme.

Mais cela en vaut la peine parce que tu n'as plus à t'inquiéter des fuites de mémoire, ce qui veut dire que tu n'as même pas à les chercher.

0
répondu s. heller 2018-02-20 14:35:23