4

Possible Duplicate:
Simple C implementation to track memory malloc/free?

I need to know how much memory I have used till now in a C program and here is the pseudo code

#include <stdio.h>

int usedMemory =0;

void *MyMalloc(int size){
 usedMemory = usedMemory +size ;
 return malloc(size);
}

void MyFree(void *pointer){
/*****************what should i write here????*************/
}
int main(int argc, char *argv[])
{
    char *temp1= (char *)MyMalloc(100);
    char *temp2= (char *)MyMalloc(100);

    /*......other operations.........*/

    MyFree(temp1);
    MyFree(temp2);

    return 0;
}

Can anyone tell me what to write in the MyFree method(which decrements the amount of memory freed from usedMemory.

Community
  • 1
  • 1
user650521
  • 583
  • 1
  • 9
  • 23
  • I ask why you want to accomplish this? Is it more of a self test for yourself or are you trying to analyze data usage? If you're just trying to track and understand memory usage take a look at the `valgrind` application that is freely available. – Grambot Nov 24 '11 at 16:14
  • 1
    What if `malloc` fails? Try `void *MyMalloc(int size) { void *tmp = malloc(size); if (tmp) usedMemory += size; return tmp; }` instead :) – pmg Nov 24 '11 at 16:20
  • Removed `C++` tag, as the question is specially about `C`. – Nawaz Nov 24 '11 at 16:21
  • @Nawaz: Not necessarily; the OP casts the void pointer, indicating that this is C++. – Kerrek SB Nov 24 '11 at 16:22
  • 1
    @Kerrek: or the OP has a bug (missing `` and consequently improper use of `malloc`) and used the cast to shut the compiler up (and keep the bug). If it were C++ the included header would have been `` or `` or some other thing with no trailing `.h` :-) – pmg Nov 24 '11 at 16:28

5 Answers5

11

You could allocate few extra bytes more than asked, and store the size in the extra bytes, so that you could know the size later on, in MyFree function, with little calculation as:

unsigned long int usedMemory = 0;

void *MyMalloc(int size)
{
  char *buffer = (char *) malloc(size + sizeof(int)); //allocate sizeof(int) extra bytes 
  if ( buffer == NULL) 
      return NULL; // no memory! 

  usedMemory += size ;      
  int *sizeBox = (int*)buffer;
  *sizeBox = size; //store the size in first sizeof(int) bytes!
  return buffer + sizeof(int); //return buffer after sizeof(int) bytes!
}

void MyFree(void *pointer)
{
   if (pointer == NULL)
       return; //no free

   char *buffer = (char*)pointer - sizeof(int); //get the start of the buffer
   int *sizeBox = (int*)buffer;
   usedMemory -= *sizeBox;
   free(buffer);
}
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 3
    Be aware that if `malloc` returns blocks with greater alignment than `sizeof(int)` then this returns unaligned memory, and that `int` is permitted to be smaller than `size_t` anyway. For a quick hack on a particular platform, just use whatever integer type seems reasonable with that in mind, which of course might well be `int`. – Steve Jessop Nov 24 '11 at 16:30
  • As Steve says -- best to figure out the maximum alignment, allocate *that* much more and then write the int at the beginning of that extra piece. – Kerrek SB Nov 24 '11 at 16:35
  • @SteveJessop: Honestly, I don't know much about alignment, so can't make it any better in that regard (I'm not confident). Feel free to edit this answer, or post a new answer so I can learn alignment issues as well. – Nawaz Nov 24 '11 at 16:35
  • It's difficult to portably detect alignment requirements. In C++11 and C1X, you should move the pointer on by the greater of `sizeof(int)` and `alignof(max_align_t)` in order to make space for an `int` without dis-aligning the allocation. In C99 you can play fairly safe with something like `sizeof(union { long double a; intmax_t b; void *c; })`, but that will probably waste space. – Steve Jessop Nov 24 '11 at 16:44
  • isn't it possible to allocate a struct{ int a; void* b} and the compare the adresses of a and b? the difference should give you the exact distance between those possibly alligned blocks, shouldn't it? (assuming this difference is the same every time...) – xmoex Nov 24 '11 at 16:56
  • 1
    @xmoex: good point, if you do `struct GetAlignment {char c; T t;};`, then `offsetof(struct GetAlignment, t)` is guaranteed to be a multiple of the alignment requirement of the type `T`. And in practice will be equal to it unless the implementation adds pointless excess padding to the structure. So if you throw everything that you think might have a large alignment requirement into a union, call that `T`, then you get the worst alignment requirement, *provided the implementation doesn't define any additional types that you don't know about it*. – Steve Jessop Nov 25 '11 at 10:02
2

In C++, you could keep a global std::map<void*, std::size_t> around to track the size of each allocated block; your own allocator function would register the size when allocating, and the deallocation function would remove the entry. (Update: Or do as the linked question suggests and allocate a bit more memory and save the size there.)

The more fundamental problem is that this will probably only be of very limited use in a typical C++ program: Allocations there are done predominantly in two ways: 1) through explicit new expressions, which call ::operator new(), which in turn (usually) calls malloc(), and 2) through std::allocator<T>::allocate(), which on many platforms is implemented in terms of ::operator new().

The problem is that you don't have control over the specifics of your platform. You can replace the global operator-new to use your own MyMalloc(), but the default std::allocator might use malloc() directly and thus not be affected by that.

A cleaner approach for debugging purposes is to use an external tool like valgrind to track heap usage. For permanent internal use, tracking the allocation sizes is going to cause a significant performance hit, too.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
2

You could allocate memory and store its size in the allocated block (error checking omitted for brevity):

unsigned int totalAlloc = 0;

void *MyAlloc(unsigned int size)
{
    void *p;
    totalAlloc += size;

    p = malloc(size + sizeof(int));
    *(int *) p = size;
    return (void *)(((int *) p) + 1)
}

void MyFree(void *ptr)
{
    ptr = (void *)(((int *) ptr) -1 );
    totalAlloc -= * (int *) ptr;
    free(ptr);
}

This code actually reserves more memory than requested in order to store the block's size in the (usually) first four bytes. This information can then be retrieved later on when you free the memory.

Linus Kleen
  • 33,871
  • 11
  • 91
  • 99
  • 2
    The problem is that you no longer return a well-aligned pointer, which in principle causes undefined behaviour all over the map. – Kerrek SB Nov 24 '11 at 16:31
  • That I don't get. Shouldn't this in principle be an allocation of "just 4 bytes more"? If I chose to allocate an array of `char` and - by principle - begin writing data to that array at index 5, the memory is still properly allocated, isn't it? – Linus Kleen Nov 24 '11 at 16:46
  • It's allocated, but not aligned right. – Kerrek SB Nov 24 '11 at 16:47
  • 1
    @Linus: suppose your C implementation requires 8-alignment for some builtin type T (this is rare, but permitted by the standard -- T might be `long long`, or `double`). Then `malloc` will return an address that is 8-aligned. You add 4 to the pointer, so the address you return is not 8-aligned. Therefore if a caller does `T *buf = MyAlloc(sizeof(T)); if (buf) {*buf = 0;}` they get undefined behavior. – Steve Jessop Nov 24 '11 at 16:51
0

You need to manage a list of all malloc() you have done with pointer + size. Then you can search for the size in that list, and decrement it in free().

Check for example in that example how they are doing: http://developers.sun.com/solaris/articles/lib_interposers_code.html#malloc_interposer.c

You might have other possibilities to track memory, like:

  • Valgrind with massif tool for tracking memory usage over time. You can even generate png output graphics
  • Interposed libraries. You can found some libraries that you can use by LD_PRELOAD=thelib.so ./yourprogram, and they will output some statistics like jemalloc

(A side note, please accept some answers to your question !)

tito
  • 12,990
  • 1
  • 55
  • 75
0

you could try something like this... i'd strongly recommend to use this only for debugging purpose!

#define MAXMEMBLOCKS 10000

typedef struct {
    int size;
    void* ptr;
} memblock;

typedef struct {
    int totalSize;
    int current;
    memblock memblocks[MAXMEMBLOCKS];
} currentMemory;

currentMemory mem;

void *MyMalloc(int size) {
    if (mem.current < MAXMEMBLOCKS) {
        mem.current += size;
        mem.memblocks[mem.current].size = size;
        mem.memblocks[mem.current].ptr = malloc(size);
        return mem.memblocks[mem.current++].ptr;
    } else {
        // you needed more memblocks than estimated
        return NULL;
    }
};

int MyFree(void *pointer) {
    int i;
    for (i = 0; i < mem.current; i++) {
        if (mem.memblocks[i].ptr == pointer) {
            mem.totalSize -= mem.memblocks[i].size;
            free(mem.memblocks[i].ptr);
            mem.current--;
            return 0;
        }
    }
    // you tried to free a block wich hasn't been allocated through MyMalloc()
    return -1;
}
xmoex
  • 2,602
  • 22
  • 36