OVH Cloud OVH Cloud

debug de fuites memoire

64 réponses
Avatar
3dsman
salut!
je suis a la recherche d'un outil efficace et pas trop compliquer pour
detecter les fuites memoires dans mes softs.
quelqu'un en aurais il un bien a me conseiller?
merci

10 réponses

1 2 3 4 5
Avatar
Jean-Marc Desperrier
3dsman wrote:
je suis a la recherche d'un outil efficace et pas trop compliquer pour
detecter les fuites memoires dans mes softs.
quelqu'un en aurais il un bien a me conseiller?


Sous Windows, le must est clairement :
http://www.codeproject.com/tools/leakfinder.asp

Avec les symboles debug il te donne une pile des appels ayant fuit avec
un outils graphique pour les visualiser.

Sinon cf article du linux journal :
http://www.linuxjournal.com/xstatic/articles/lj/0087/4681/4681s2.html

Je recommanderais ccmalloc, dmalloc, ...

Avatar
Michel Michaud
Dans le message 42d35b46$0$26418$,
je suis a la recherche d'un outil efficace et pas trop compliquer
pour detecter les fuites memoires dans mes softs.
quelqu'un en aurais il un bien a me conseiller?


Juste un mot pour préciser qu'il y a déjà ce qu'il faut sous
Visual C++, si jamais c'est ce que tu utilises...

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

Avatar
kanze
Arnaud Meurgues wrote:
wrote:

Ça ressemble drôlement à ce que je fais moi-même.


Ça doit être oins bien fini. J'ai fait ça rapidement pour un
problème ponctuel.


Je ne sais pas. D'après la description que tu as donnée dans un
autre posting, il a l'air bien mieux conçu que la mienne. La
mienne, aussi, a commencé comme une solution rapide à un
problème ponctuel. Ensuite, j'ai ajouté des features, un après
l'autre. En dur, direct dans le code -- je n'avais pas pensé au
visiteur.

En général, générer un stack walkback n'est pas trop
difficile. Mais la technique dépend étroitement de la
machine, et l'afficher autrement qu'en hexadécimal exigerait
pas mal de code aussi.


Ça, ça m'intéresse bigrement. J'avais regardé un moment
comment faire, mais je m'étais laissé décourager (je n'avais
pas assez de temps non plus). En plus, mon code était supposé
fonctionner sur plusieurs plateforme (vu les différence
d'implémentation des list, ça n'a pas été sans mal,
d'ailleurs).


Le principe de base est assez simple : il faut éventuellement
s'assurer que toute la pile est en mémoire (toujours le cas sur
des IA-32, mais il faut une instruction machine spéciale sur un
Sparc). Ensuite, tu obtiens l'adresse de départ -- soit en
pêchant dans un buffer de setjmp, soit en prenant l'adresse
d'une variable locale. Puis, il ne reste plus que des
reinterpret_cast et de l'arithmétique sur des pointeurs pour
régarder ce que tu veux dans la pile. En fait, la plus
difficile, en général, c'est de savoir où se trouvent exactement
dans la pile les informations que tu cherches.

Pour l'architecture Intel, c'est aussi simple que :

class StackFrameIter
{
public:
StackFrameIter() ;

bool isDone() const ;
void next() ;
unsigned current() const ;

private:
struct Frame
{
Frame* next ;
unsigned returnAddr ;
} ;
Frame* myCurrent ;
} ;

inline
StackFrameIter::StackFrameIter()
{
void* fp = &fp + 1 ;
myCurrent = static_cast< Frame* >( fp )->next ;
}

inline bool
StackFrameIter::isDone() const
{
return myCurrent == NULL ;
}

inline void
StackFrameIter::next()
{
if ( ! isDone() ) {
myCurrent = myCurrent->next ;
}
}

inline unsigned
StackFrameIter::current() const
{
return myCurrent->returnAddr ;
}

Au moins sous Linux. Mais j'imagine que la seule chose qui
risque de changer sous Windows, c'est ce que tu ajoutes à
l'adresse de fp dans le constructeur. (Selon le compilateur, il
se peut aussi qu'il vaut mieux que le constructeur ne soit pas
inline, voir qu'on se sert d'une fonction complétement séparée
pour obtenir l'adresse de début. Mais le code ici fonctionne
sous Linux avec des versions récentes de g++, compilé sans
optimisation.)

Note aussi qu'avec g++, tu as des fonctions
__builtin_return_address et __builtin_frame_address, chacun qui
prend un paramètre pour spécifier le profondeur.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Alexis Nikichine
3dsman wrote:
salut!
je suis a la recherche d'un outil efficace et pas trop compliquer pour
detecter les fuites memoires dans mes softs.
quelqu'un en aurais il un bien a me conseiller?


Pas d'avis pour windows, mais sous Linux, je ne saurais trop recommander
valgrind (http://valgrind.org/ ) que je n'ai entendu personne d'autre
mentionner, enfin, au moins dans ce fil de discussion. Ce qui est bien,
c'est qu'il ne nécessite pas de recompiler quoi que ce soit, il procède
à une "éxecution instrumentée", dans un émulateur ad hoc, et renvoie des
stack trace pertinents des instants où on a mal utilisé la mémoire.

Enfin, c'est quand même mieux si les binaires leakants sont compilés
avec des symboles de debug, les stack trace sont plus lisibles :-)

Alexis


--
Some domain is free

Avatar
AG
Michel Michaud wrote:

Dans le message 42d35b46$0$26418$,

je suis a la recherche d'un outil efficace et pas trop compliquer
pour detecter les fuites memoires dans mes softs.
quelqu'un en aurais il un bien a me conseiller?



Juste un mot pour préciser qu'il y a déjà ce qu'il faut sous
Visual C++, si jamais c'est ce que tu utilises...

Est ce que vous parlez de :


_CrtSetReportMode()
_malloc_dbg()

etc... ?


Avatar
Arnaud Meurgues
wrote:

l'autre. En dur, direct dans le code -- je n'avais pas pensé au
visiteur.


Oui. J'ai longtemps hésité sur la manière d'utiliser le visiteur. Je me
demandais si c'était à lui de stocker les blocs ou si cela devait être
fait par l'allocateur. Je n'ai pas trouvé de réponse satisfaisante.

Peut-être que les stocker dans l'allocateur et ne fournir au visiteur
que des itérateurs sur la liste des blocs mémoire de l'allocateur serait
une meilleure solution ?

Le principe de base est assez simple : il faut éventuellement
s'assurer que toute la pile est en mémoire (toujours le cas sur
des IA-32, mais il faut une instruction machine spéciale sur un
Sparc).


Ah ? Sur Sparc, toute la pile n'est pas nécessairement en mémoire ?

Ensuite, tu obtiens l'adresse de départ -- soit en
pêchant dans un buffer de setjmp,


Ah. Je ne suis pas (plus) très familier avec ce genre de fonctions. Je
n'ai jamais eu à m'en servir.

d'une variable locale. Puis, il ne reste plus que des
reinterpret_cast et de l'arithmétique sur des pointeurs pour
régarder ce que tu veux dans la pile. En fait, la plus
difficile, en général, c'est de savoir où se trouvent exactement
dans la pile les informations que tu cherches.


Ben oui. Ça nécessite une bonne documentation du compilateur, de l'OS et
du matériel pour savoir comment il organise la pile.

Au moins sous Linux. Mais j'imagine que la seule chose qui
risque de changer sous Windows, c'est ce que tu ajoutes à
l'adresse de fp dans le constructeur. (Selon le compilateur, il
se peut aussi qu'il vaut mieux que le constructeur ne soit pas
inline, voir qu'on se sert d'une fonction complétement séparée
pour obtenir l'adresse de début. Mais le code ici fonctionne
sous Linux avec des versions récentes de g++, compilé sans
optimisation.)

Note aussi qu'avec g++, tu as des fonctions
__builtin_return_address et __builtin_frame_address, chacun qui
prend un paramètre pour spécifier le profondeur.


Malheureusement, il se trouve que g++ est un des compilateurs que je
n'utilise pas (moi, c'est msvc sous Windows, CC sous Solaris, aCC sous
HP, essentiellement).

En plus, j'aurais aimé trouver les noms des fonctions, plutôt que
simplement les adresses. Et ça, ça nécessite de savoir lire les infos de
debug...

Arnaud

Avatar
Jean-Marc Bourguet
Arnaud Meurgues writes:

Ah ? Sur Sparc, toute la pile n'est pas nécessairement en mémoire ?


Non. Sparc a une "pile" de registres. Lors d'un appel de fonction,
on change les registres visibles (en fait, certains restent visibles
et d'autres changent simplement de nom, ce sont ceux utilise pour le
passage de parametres). Il y a une interruption en cas de depassement
de capacite de la pile et alors on copie les registres dans la pile en
memoire. Il faut donc generer cette interruption pour etre sur que
tout est bien en memoire et non dans des registres innaccessibles
(surtout qu'un de ces registres est celui qui contient l'emplacement
du "frame" suivant).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Michel Michaud
Dans le message 42d5044f$0$31208$,
Michel Michaud wrote:
Juste un mot pour préciser qu'il y a déjà ce qu'il faut sous
Visual C++, si jamais c'est ce que tu utilises...

Est ce que vous parlez de :


_CrtSetReportMode()
_malloc_dbg()


Plutôt

#include <crtdbg.h>

int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...

À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/


Avatar
AG
Michel Michaud wrote:

#include <crtdbg.h>

int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
Ok, c'est ce à quoi je pensais. j'utilise _CRTDBG_CHECK_ALWAYS_DF en sus.


AG.

Avatar
Gabriel Dos Reis
Arnaud Meurgues writes:

[...]

| > Note aussi qu'avec g++, tu as des fonctions
| > __builtin_return_address et __builtin_frame_address, chacun qui
| > prend un paramètre pour spécifier le profondeur.

mais ces machins ne marchent pas bien pour une profondeur autre que zéro.

| Malheureusement, il se trouve que g++ est un des compilateurs que je
| n'utilise pas (moi, c'est msvc sous Windows, CC sous Solaris, aCC sous
| HP, essentiellement).
|
| En plus, j'aurais aimé trouver les noms des fonctions, plutôt que
| simplement les adresses. Et ça, ça nécessite de savoir lire les infos
| de debug...

DWAFT ou stabs sont assez répandus.
Et si utilisais g++, tu pourrais essayer de regarder -finstrument-functions

-- Gaby
1 2 3 4 5