Kanishk
Kanishk

Reputation: 177

A clarification regarding how free() works in C -

My question is regarding when using free() is appropriate in C. I'm using gcc 4.3.2.

Suppose, if had to deallocate a bunch of memory, in a linked list, the ideal way to go about it is(I'm guessing):

int freeLL(node *a)
{
    if(a->next != NULL)
         freeLL(a->next);
    free(a);
    return 0;
}

Now, suppose I were to do a similar thing on the following ADT:

A pointer "VertexNode" which has 2 more pointers: "Vertex" and "Edge"(say). Equivalent to saying:

struct vertexnode
{
     vertex *v;
     edge *e;
}
typedef struct vertexnode* VertexNode;

Later, when initializing an instance, I'll do something like -

VertexNode V = malloc(sizeof(struct vertexnode));
V->v = malloc(sizeof(vertex));

So, ultimately while freeing: I used the same analogy as I used for the linked list.

free(V->v);
free(V);

This gave a runtime error, and when I commented out "free(V->v)", the program worked fine. My questions are:

a) Is simply doing free(V) sufficient? I mean, does free() work recursively on all pointers inside a given pointer?

b) If not, is there a memory leak in this case? And how do I ideally prevent that?

c) Lastly, is there a way I can keep track of how many bytes were allocated by malloc() and how many of them were freed by free()?

I'm very sorry for the long question. Thank you in advance for your time and patience.

Upvotes: 1

Views: 457

Answers (6)

Mike
Mike

Reputation: 49373

Basically the thing to remember is calls to malloc()/free() should be 1:1. If I call malloc() to get some memory, I need to call free() to return it when I'm done.

This answers question a), no it's not recursive. (or else one call to free() would be good enough).

b) You bet there'd be a memory leak! Think about some simple code:

typedef struct pointless {
    struct pointless * next;
}pl;

pl * head = malloc(sizeof(pl)); // head gets 4 bytes
pl->next = malloc(sizeof(pl));  // head->next gets 4 bytes
free(head);  // head's allocated 4 bytes are deleted

Obviously this is a pointless list, since it just points to the next empty element, but it illustrates the point. My total list has 8 bytes allocated to it (4 for head, 4 for head's next). When I call free() it works on head's 4 bytes, but that's it.

This is a good thing it works this way! Think about deleting a single item from the middle of a linked list, you want to free the memory for that node, but not the whole thing! However given my above example, you'd have a memory leak as head->next wasn't free'd; and once you call free(head) there's no guarantee that you can access head->next anymore. It's possible of course... but UB at this point.

c) memory management at that level is done by the OS. If you want to keep track of how much you allocated/freed you'd have to do something like:

int total_mem = 0;

head = malloc((total_mem += sizeof(pl)));

free(head);
total_mem -= sizeof(head);

Of course you could put wrappers around the malloc() and free() calls to do the math for you which would be much more manageable, but you get the idea.

Upvotes: 1

ant2009
ant2009

Reputation: 22486

For a complete memory management I would to have a memory pool. This would take away all the pain of having to call a number of free's for each malloc that is called. I use Apache Portable runtime (APR) for doing memory pooling. Just allocate a chunk of memory at the start to initialize. The allocate as much as you want for each pointer. Then at the end just make one call to free all the memory. This is much more efficient then doing lots of mallocs and frees that leads to memory leaks.

As a side note. I suggest you use valgrind to test you application if you don't use the memory pool. In fact you should always use valgrind.

Upvotes: 2

Ronaldo Nazarea
Ronaldo Nazarea

Reputation: 366

A: free() does not work recursively. - If you're on the ADT concept, then I suggest you perform the allocation inside the type by creating a createVertexNode() function, and do the checking and deallocation inside a freeVertexNode() function

B: If you wasn't able to free it, then it will be a memory leak - you can avoid it by making sure your ADT functions check and free the memory it allocates, or ...

C: Use a memory leak checker. Visual Studio has a built-in one, or use other such as valgrind or Rational Purify. I'm sure there are more free open source libraries that, at the simplest, override the malloc() and free() calls

Upvotes: 1

tomahh
tomahh

Reputation: 13651

No, free does not work recursively, therefore you would indeed have memory leaks. The runtime error you are occuring is probably realated to a logic error (maybe V->v is NULL or you did not alloc it before freeing).

If you are working with linux, using valgrind can help you profiling your program and mention leak errors. Compile using cc *.c -ggdb and then run valgrind --leakcheck=full ./a.out will output leak errors.

Upvotes: 2

TieDad
TieDad

Reputation: 9889

To answer your question:

a) No. free() doesn't recursively free struct's member pointers.

b) Yes, there is memory leak in that case. You have to free all allocated memory with your code.

c) You may use tool to check memory leak, such as valgrind, that's easy. And I know some projects implements their own memory management, they wrap malloc and free in their own APIs, so that you can track memory usage in their APIs.

Upvotes: 2

Thorsten Dittmar
Thorsten Dittmar

Reputation: 56697

The thing is: you need to make sure that the pointer you're trying to free is actually initialized.

I'd also check whether V->v is not NULL before calling free on it (see my comment on your question).

free is not "recursive". You're leaking memory if you don't free e and v (in your example) as well.

Upvotes: 1

Related Questions