Bonjour à tous,
Aujourd'hui, je viens vous voir en réclamant votre aide après de longs jours à résoudre un problème qui me prend énormément la tête.
Je pourrais faire comme j'ai fait jusqu'à aujourd'hui, c'est-à-dire de résoudre mes problèmes par moi-même mais sur un mois de projet, je n'ai que 6 minables fichiers sources qui m'ont posés une bonne dizaines de problèmes. Ces problèmes se passant uniquement à la fin d'éxecution du programme, les debuggers ne m'aident pas.
Donc voici mon problème :
Je reprend le principe du détecteur de fuite de mémoire élaboré par loulou. Merci à lui.
Je surcharge donc dans mon programme les operator new, new[], delete et delete[]. Cependant quand je compiles avec MSVC mon operator delete est appelé plusieurs fois alors que je le demande pas.
Du côté de GCC, mon programme, apparement appelle une fois l'operateur delete.
Je me disais qu'éventuellement, le prototype de ma surcharge pourrait poser problème dans le cas où la librarie standard se retrouve à l'utiliser. Je suis donc venu à commenter la ligne 76 de MemLeakTracker.cpp et j'ai remarqué que ça fonctionne. Il y a donc un problème au niveau de la libération de mémoire venant d'un bloc de la bibliothèque standard. Donc comment faire en sorte que la bibliothèque standard n'utilise pas ma surcharge delete ?
Car même si j'arrive à libérer la mémoire allouée par la bibliothèque standard, celle-ci est censé avec ma surcharge delete demande de recréer une instance de MemLeakTracker qui a été précédement détruit parce que c'est la fin du programme... Mais si j'affiche à quelque chose dans la console lors de la création d'une instance de MemLeakTracker, je me rend compte qu'une seule instance est bien créer. Donc la bibliothèque standard utilise mon operator delete surchargé qui appelle une fonction qui n'existe pas mais qui est quand même exécuté. (c.f. sortie MSVC) Je suis perdu...
EDIT : J'ai remarqué que j'ai le même problème quand j'utilise uniquement le MemoryManager de loulou. MSVC, tu me fais vraiment c****...
Voici mes sources :
- MemLeakTracker.h
Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 #ifndef MEM_LEAK_TRACKER__H #define MEM_LEAK_TRACKER__H #include <map> #include <iostream> #include <cstdlib> struct MemBlock { const char* file; unsigned short int line; size_t size; }; class MemLeakTracker { public: static MemLeakTracker& getInstance(); void* const allocate(const char* const file, unsigned short int const line, size_t const size); void deallocate(void* pointer); private: MemLeakTracker(); ~MemLeakTracker(); std::map<void*, MemBlock> m_blocks; std::map<void*, MemBlock>::iterator m_it; }; void* operator new(size_t const size, const char* const file, unsigned short int const line); void* operator new[](size_t const size, const char* const file, unsigned short int const line); void operator delete(void* pointer) throw(); void operator delete[](void* pointer) throw(); #endif //MEM_LEAK_TRACKER__H #define new new(__FILE__, __LINE__) #define free delete- MemLeakTracker.cpp
Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 #include <sstream> #include "GameEngine/Common/Debug/MemLeakTracker.h" #include "GameEngine/Common/Debug/MemLeakTrackerOff.h" MemLeakTracker::MemLeakTracker() { std::cout << "Creation instance MemLeakTracker" << std::endl; } MemLeakTracker::~MemLeakTracker() { if(!m_blocks.empty()) { unsigned long long totalSize = 0; size_t size; std::wcout << m_blocks.size() << " memory leaks detected !\n"; for(m_it = m_blocks.begin(); m_it != m_blocks.end(); m_it++) { std::wcout << " At 0x" << m_it->first << " in " << m_it->second.file << " at line " << m_it->second.line << " ("; size = m_it->second.size; std::wcout << size << "B)\n"; totalSize += size; free(m_it->first); //Crash with MSVC if I let this line } std::wcout << totalSize << "B has been freed !\n"; } } MemLeakTracker& MemLeakTracker::getInstance() { static MemLeakTracker instance; return instance; } void* const MemLeakTracker::allocate(const char* const file, unsigned short int const line, size_t const size) { void* const pointer = malloc(size); MemBlock myBlock; myBlock.file = file; myBlock.line = line; myBlock.size = size; m_blocks[pointer] = myBlock; return pointer; } void MemLeakTracker::deallocate(void* pointer) { m_it = m_blocks.find(pointer); if(m_it == m_blocks.end()) //If the pointer is not in the memory block stack { std::wcout << "Trying to delete " << pointer << " which is not in the stack" << std::endl; //free(pointer); std::wcout << "Success" << std::endl; } else { std::wcout << "Trying to delete " << pointer << std::endl; m_blocks.erase(pointer); free(pointer); std::wcout << "Success to delete " << pointer << std::endl; } } void* operator new(size_t const size, const char* const file, unsigned short int const line) { return MemLeakTracker::getInstance().allocate(file, line, size); } void* operator new[](size_t const size, const char* const file, unsigned short int const line) { return MemLeakTracker::getInstance().allocate(file, line, size); } void operator delete(void* pointer) throw() { MemLeakTracker::getInstance().deallocate(pointer); } void operator delete[](void* pointer) throw() { MemLeakTracker::getInstance().deallocate(pointer); }- MemLeakTrackerOff.h
Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 #undef new #undef free- main.cpp
Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 #include <iostream> #include "GameEngine/Common/Debug/MemLeakTracker.h" int main() { char* a = new char; return 0; }
Et les sorties :
- Avec MSVC :
CRASHEnvoyé par console
- Avec GCC :
SUCCESSFULLEnvoyé par console
Quelqu'un peut m'aider S.V.P. ?
Et aussi j'ai une question qui n'a pas grand chose à avoir mais je vais quand même la poser. Quand on compile un programme avec une bibliothèque directement (donc pas linkage statique ni dynamique), pourquoi le programme, une fois compilé en Debug et même Release (avec aussi des optimizations de taille) inclu même les fonctions non utilisés. Pourquoi n'y a t-il pas d'optimisation de la part des compilateurs pour ça ?
Je m'explique, que je compile en mode Debug ou mode Release (et même avec les optimisations de taille) et que j'inclu comme ça au hasard des fichiers headers que j'utilise même pas, pourquoi le compilateur garde ces fichiers dans mon binaire ? Car je trouve ça assez étrange vu la complexité des compilateurs, qu'une telle fonctionnalitée n'existe pas.
Bonne journée et merci d'avance.
Partager