How to Track Memory Allocations in C++ (Especially New/Delete)

How to track memory allocations in C++ (especially new/delete)

I would recommend you to use valgrind for linux. It will catch not freed memory, among other bugs like writing to unallocated memory. Another option is mudflap, which tells you about not freed memory too. Use -fmudflap -lmudflap options with gcc, then start your program with MUDFLAP_OPTIONS=-print-leaks ./my_program.

Here's some very simple code. It's not suitable for sophisticated tracking, but intended to show you how you would do it in principle, if you were to implement it yourself. Something like this (left out stuff calling the registered new_handler and other details).

template<typename T>
struct track_alloc : std::allocator<T> {
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;

template<typename U>
struct rebind {
typedef track_alloc<U> other;
};

track_alloc() {}

template<typename U>
track_alloc(track_alloc<U> const& u)
:std::allocator<T>(u) {}

pointer allocate(size_type size,
std::allocator<void>::const_pointer = 0) {
void * p = std::malloc(size * sizeof(T));
if(p == 0) {
throw std::bad_alloc();
}
return static_cast<pointer>(p);
}

void deallocate(pointer p, size_type) {
std::free(p);
}
};

typedef std::map< void*, std::size_t, std::less<void*>,
track_alloc< std::pair<void* const, std::size_t> > > track_type;

struct track_printer {
track_type * track;
track_printer(track_type * track):track(track) {}
~track_printer() {
track_type::const_iterator it = track->begin();
while(it != track->end()) {
std::cerr << "TRACK: leaked at " << it->first << ", "
<< it->second << " bytes\n";
++it;
}
}
};

track_type * get_map() {
// don't use normal new to avoid infinite recursion.
static track_type * track = new (std::malloc(sizeof *track))
track_type;
static track_printer printer(track);
return track;
}

void * operator new(std::size_t size) throw(std::bad_alloc) {
// we are required to return non-null
void * mem = std::malloc(size == 0 ? 1 : size);
if(mem == 0) {
throw std::bad_alloc();
}
(*get_map())[mem] = size;
return mem;
}

void operator delete(void * mem) throw() {
if(get_map()->erase(mem) == 0) {
// this indicates a serious bug
std::cerr << "bug: memory at "
<< mem << " wasn't allocated by us\n";
}
std::free(mem);
}

int main() {
std::string *s = new std::string;
// will print something like: TRACK: leaked at 0x9564008, 4 bytes
}

We have to use our own allocator for our map, because the standard one will use our overridden operator new, which would result in an infinite recursion.

Make sure if you override operator new, you use the map to register your allocations. Deleting memory allocated by placement forms of new will use that delete operator too, so it can become tricky if some code you don't know has overloaded operator new not using your map, because operator delete will tell you that it wasn't allocated and use std::free to free the memory.

Also note, as Pax pointed out for his solution too, this will only show leaks that are caused by code using our own defined operator new/delete. So if you want to use them, put their declaration in a header, and include it in all files that should be watched.

Keeping track of used memory with overloaded new and delete operator?

A bit annoying, isn't it? free knows how much memory there is to free, but won't tell you.

The practical solution is to add an extra sizeof(size_t) to the malloc request, and use those first bytes of the returned allocation to store sz. In operator delete, you do the reverse: you look for the sizeof(size_t) bytes preceding ptr.

So the bit of code you'd get is memory-=static_cast<size_t*>(prt)[-1];. The [-1] looks scary, I know. One of the few cases where it makes sense.

new and delete Memory Management out of scope

The key insight which you're probably missing here is that delete does not have any relationship with a specific variable - it has a relationship with a specific object stored at a certain memory address. It's commonly stated as a rule that "any object allocated with new must be deallocated with delete." But note the use of the word object - not variable.

Consider:

Fraction* a = new Fraction(3,4);
Fraction* b = a;
delete b;

In this example we deleted b, which points to the Fraction object allocated on the first line. We also could have deleted a, which pointed to the same Fraction object. As long as we delete every object allocated with new (regardless of which pointer variable we use to access the object), there is no memory leak. Also note that if we delete both a and b then we have an error (undefined behavior via a double-delete).

Who deletes the memory allocated during a new operation which has exception in constructor?

You should refer to the similar questions here and here.
Basically if the constructor throws an exception you're safe that the memory of the object itself is freed again. Although, if other memory has been claimed during the constructor, you're on your own to have it freed before leaving the constructor with the exception.

For your question WHO deletes the memory the answer is the code behind the new-operator (which is generated by the compiler). If it recognizes an exception leaving the constructor it has to call all the destructors of the classes members (as those have already been constructed successfully prior calling the constructor code) and free their memory (could be done recursively together with destructor-calling, most probably by calling a proper delete on them) as well as free the memory allocated for this class itself. Then it has to rethrow the catched exception from the constructor to the caller of new.
Of course there may be more work which has to be done but I cannot pull out all the details from my head because they are up to each compiler's implementation.

using new and delete inside class function

At least as I see things, you really only have two sane choices here. One is for the caller to handle all the memory management. The other is for the callee to handle all the memory management.

But what you're doing right now (callee handles allocation, caller handles de-allocation) is a path to madness and memory leaks.

If the caller is going to manage the memory, this all becomes fairly simple:

const char *myIOT2::_devName(char *ret, size_t maxlen)
{
if (strcmp(addGroupTopic, "") != 0)
{
snprintf(ret, maxlen, "%s/%s/%s", prefixTopic, addGroupTopic, deviceTopic);
}
else
{
snprintf(ret, maxlen, "%s/%s", prefixTopic, deviceTopic);
}
return ret;
}

If the callee is going to handle all the memory management, you'd normally use std::string. Since you're on an Arduino, however, std::string isn't available, and you need to use their own String class instead. Either way, you simply allocate a String object and put your contents into it. It takes care of the actual memory allocation to hold the contents, and will free its contents when the String object is destroyed.

Given the small amount of memory normally available on an Arduino, having the caller allocate the memory is usually going to work out better. But (especially if this is something that doesn't happen very often, so you won't run into heap fragmentation problems) allocating space on the heap can work reasonably well also.

But I'll repeat: trying to mix memory management so the callee allocates and the caller deletes...is the stuff of nightmares. When you read about C++ circa 1993, and hear about lots of problems with memory leaks...this is exactly the sort of thing that led to them.

Best way to handle memory allocation in C?

Part of the confusion is that it is inherently more difficult in C. malloc and free are similar to new and delete: malloc allocates new memory, and returns a pointer to that memory. free makes that memory available again, so long as it's memory that was allocated using malloc. Otherwise, it just makes hash of some chunk of memory. It doesn't care.

The important thing with malloc/free is to decide on and consistently maintain a disciplined use. Here are some hints:

ALWAYS check the returned pointer from malloc for NULL

if((p = (char *) malloc(BUFSIZ)) == NULL {
/* then malloc failed do some error processing. */
}

For belt and suspenders safety, set a pointer to NULL after freeing it.

free(p);
p = NULL ;

try to malloc and free a chunk of memory within the same scope if possible:

 {  char * p ;
if((p = malloc(BUFSIZ)) == NULL {
/* then malloc failed do some error processing. */
}

/* do your work. */

/* now you're done, free the memory */

free(p);
p = NULL ; /* belt-and suspenders */
}

When you can't, make it clear that what you're returning is malloc'ed memory, so the caller can free it.

 /* foo: do something good, returning ptr to malloc memory */
char * foo(int bar) {
return (char *) malloc(bar);
}

How does the delete in C++ know how many memory locations to delete

There is only delete operator, free exist only as function. Under C++, you are encouraged to use new/delete over malloc()/free().


There is an internal "magic" in delete operator. When an array is created with new[], the size of array is stored in the metadata at the memory block. delete[] makes use of that information.

All this is of course compiler-, OS-, optimizer- and implementation-dependent.



Related Topics



Leave a reply



Submit