Here is a quick and easy way to profile memory of C++ programs by simply overriding the default new/delete operators. Just add this to your program source (you don't even have to call it):
/* Who called me? */
void* caller()
{
// The target is the caller's caller, so three functions back
const int target = 3;
void* returnaddresses[target];
if (backtrace(returnaddresses, target) < target) {
return NULL;
}
return returnaddresses[target-1];
}
void* operator new(size_t size) throw(std::bad_alloc) {
void* ret = malloc(size);
if (!ret) throw std::bad_alloc();
fprintf(stderr, "allocate: %p %d bytes from %p\n", ret, size, caller());
return ret;
}
void* operator new[] (size_t size) throw(std::bad_alloc) {
void* ret = malloc(size);
if (!ret) throw std::bad_alloc();
fprintf(stderr, "allocate: %p %d bytes from %p\n", ret, size, caller());
return ret;
}
void operator delete (void* data)
{
free(data);
fprintf(stderr, "free: %p\n", data);
}
void operator delete [] (void* data)
{
free(data);
fprintf(stderr, "free: %p\n", data);
}
Your program will spew output about all the new/delete allocations it performs. Run that through this awk snippet to get a useful report:
awk '/^free: / { fun[owner[$2]] -= size[$2]; delete size[$2]; delete owner[$2]; }
/^reallocate: / { fun[owner[$2]] -= size[$2]; delete size[$2]; delete owner[$2];
size[$4] = $6; owner[$4] = $9; fun[$9] += $6; }
/^allocate: / { size[$2] = $3; owner[$2] = $6; fun[$6] += $3; }
END { for(i in fun) { print i " has " fun[i] " bytes"; }}' |
sort -k3n
Alternatively, you can omit the print statements here but keep the new/delete → malloc/free connection and use the malloc/free profiler. This is handy for misbehaved programs that free new-ed things or delete malloc'd things.