Use Valgrind and its tool Massif. Its example output (a part of it):
99.48% (20,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->49.74% (10,000B) 0x804841A: main (example.c:20)
|
->39.79% (8,000B) 0x80483C2: g (example.c:5)
| ->19.90% (4,000B) 0x80483E2: f (example.c:11)
| | ->19.90% (4,000B) 0x8048431: main (example.c:23)
| |
| ->19.90% (4,000B) 0x8048436: main (example.c:25)
|
->09.95% (2,000B) 0x80483DA: f (example.c:10)
->09.95% (2,000B) 0x8048431: main (example.c:23)
So, you will get detailed information:
Here is Massif manual
You can track heap allocation as well as stack allocation (turned off by default).
PS. I just read that you're on Windows. I will leave the answer though, because it gives a picture of what you can get from a possible tool.
Microsoft have well documented memory tracking functions. However, for some reason they are not really well-known in the developer community. These are CRT debug functions. Good starting point will be CRT Debug Heap functions.
Check the following links for more details
For a generic C++ memory tracker you will need to overload the following:
global operator new
global operator new []
global operator delete
global operator delete []
any class allocators
any in-place allocators
The tricky bit is getting useful information, the overloaded operators only have size information for allocators and memory pointers for deletes. One answer is to use macros. I know. Nasty. An example - place in a header which is included from all source files:
#undef new
void *operator new (size_t size, char *file, int line, char *function);
// other operators
#define new new (__FILE__, __LINE__, __FUNCTION__)
and create a source file with:
void *operator new (size_t size, char *file, int line, char *function)
{
// add tracking code here...
return malloc (size);
}
The above only works if you don't have any operator new defined at class scope. If you do have some at class scope, do:
#define NEW new (__FILE__, __LINE__, __FUNCTION__)
and replace 'new type' with 'NEW type', but that requires changing a lot of code potentially.
As it's a macro, removing the memory tracker is quite straightforward, the header becomes:
#if defined ENABLED_MEMORY_TRACKER
#undef new
void *operator new (size_t size, char *file, int line, char *function);
// other operators
#define NEW new (__FILE__, __LINE__, __FUNCTION__)
#else
#define NEW new
#endif
and the implementation file:
#if defined ENABLED_MEMORY_TRACKER
void *operator new (size_t size, char *file, int line, char *function)
{
// add tracking code here...
return malloc (size);
}
endif
Update: to the answer of @Skizz
Since C++20, we can use std::source_location instead of macros like __FILE__
and __LINE__
.
(As this is a major simplification, I believe that it deserves a seperate answer).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With