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.