Question

programming language: C platform: ARM Compiler: ADS 1.2

I need to keep track of simple melloc/free calls in my project. I just need to get very basic idea of how much heap memory is required when the program has allocated all its resources. Therefore, I have provided a wrapper for the malloc/free calls. In these wrappers I need to increment a current memory count when malloc is called and decrement it when free is called. The malloc case is straight forward as I have the size to allocate from the caller. I am wondering how to deal with the free case as I need to store the pointer/size mapping somewhere. This being C, I do not have a standard map to implement this easily.

I am trying to avoid linking in any libraries so would prefer *.c/h implementation.

So I am wondering if there already is a simple implementation one may lead me to. If not, this is motivation to go ahead and implement one.

EDIT: Purely for debugging and this code is not shipped with the product.

EDIT: Initial implementation based on answer from Makis. I would appreciate feedback on this.

EDIT: Reworked implementation

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <limits.h>

static size_t gnCurrentMemory = 0;
static size_t gnPeakMemory    = 0;

void *MemAlloc (size_t nSize)
{
  void *pMem = malloc(sizeof(size_t) + nSize);

  if (pMem)
  {
    size_t *pSize = (size_t *)pMem;

    memcpy(pSize, &nSize, sizeof(nSize));

    gnCurrentMemory += nSize;

    if (gnCurrentMemory > gnPeakMemory)
    {
      gnPeakMemory = gnCurrentMemory;
    }

    printf("PMemAlloc (%#X) - Size (%d), Current (%d), Peak (%d)\n",
           pSize + 1, nSize, gnCurrentMemory, gnPeakMemory);

    return(pSize + 1);
  }

  return NULL;
}

void  MemFree (void *pMem)
{
  if(pMem)
  {
    size_t *pSize = (size_t *)pMem;

    // Get the size
    --pSize;

    assert(gnCurrentMemory >= *pSize);

    printf("PMemFree (%#X) - Size (%d), Current (%d), Peak (%d)\n",
           pMem,  *pSize, gnCurrentMemory, gnPeakMemory);

    gnCurrentMemory -= *pSize;

    free(pSize);
  }
}

#define BUFFERSIZE (1024*1024)

typedef struct
{
  bool flag;
  int buffer[BUFFERSIZE];
  bool bools[BUFFERSIZE];
} sample_buffer;

typedef struct
{
  unsigned int whichbuffer;
  char ch;
} buffer_info;


int main(void)
{
  unsigned int i;
  buffer_info *bufferinfo;

  sample_buffer  *mybuffer;

  char *pCh;

  printf("Tesint MemAlloc - MemFree\n");

  mybuffer = (sample_buffer *) MemAlloc(sizeof(sample_buffer));

  if (mybuffer == NULL)
  {
    printf("ERROR ALLOCATING mybuffer\n");

    return EXIT_FAILURE;
  }

  bufferinfo = (buffer_info *) MemAlloc(sizeof(buffer_info));

  if (bufferinfo == NULL)
  {
    printf("ERROR ALLOCATING bufferinfo\n");

    MemFree(mybuffer);

    return EXIT_FAILURE;
  }

  pCh = (char *)MemAlloc(sizeof(char));

  printf("finished malloc\n");

  // fill allocated memory with integers and read back some values
  for(i = 0; i < BUFFERSIZE; ++i)
  {
    mybuffer->buffer[i] = i;
    mybuffer->bools[i] = true;
    bufferinfo->whichbuffer = (unsigned int)(i/100);
  }


  MemFree(bufferinfo);
  MemFree(mybuffer);

  if(pCh)
  {
    MemFree(pCh);
  }

  return EXIT_SUCCESS;
}
Was it helpful?

Solution

You could allocate a few extra bytes in your wrapper and put either an id (if you want to be able to couple malloc() and free()) or just the size there. Just malloc() that much more memory, store the information at the beginning of your memory block and and move the pointer you return that many bytes forward.

This can, btw, also easily be used for fence pointers/finger-prints and such.

OTHER TIPS

Either you can have access to internal tables used by malloc/free (see this question: Where Do malloc() / free() Store Allocated Sizes and Addresses? for some hints), or you have to manage your own tables in your wrappers.

You could always use valgrind instead of rolling your own implementation. If you don't care about the amount of memory you allocate you could use an even simpler implementation: (I did this really quickly so there could be errors and I realize that it is not the most efficient implementation. The pAllocedStorage should be given an initial size and increase by some factor for a resize etc. but you get the idea.)

EDIT: I missed that this was for ARM, to my knowledge valgrind is not available on ARM so that might not be an option.

static size_t indexAllocedStorage = 0;
static size_t *pAllocedStorage = NULL;
static unsigned int free_calls = 0; 
static unsigned long long int total_mem_alloced = 0; 

void * 
my_malloc(size_t size){
    size_t *temp;
    void *p = malloc(size);
    if(p == NULL){
    fprintf(stderr,"my_malloc malloc failed, %s", strerror(errno));
    exit(EXIT_FAILURE);
    }

    total_mem_alloced += size;

    temp = (size_t *)realloc(pAllocedStorage, (indexAllocedStorage+1) * sizeof(size_t));
    if(temp == NULL){
        fprintf(stderr,"my_malloc realloc failed, %s", strerror(errno));
         exit(EXIT_FAILURE);
    }

    pAllocedStorage = temp; 
    pAllocedStorage[indexAllocedStorage++] = (size_t)p;

    return p;
}

void 
my_free(void *p){
    size_t i;
    int found = 0;

    for(i = 0; i < indexAllocedStorage; i++){
    if(pAllocedStorage[i] == (size_t)p){
        pAllocedStorage[i] = (size_t)NULL;
        found = 1;
        break;
        }
    }

    if(!found){
        printf("Free Called on unknown\n");
    }

    free_calls++;
    free(p);
}

void 
free_check(void) {
    size_t i;

    printf("checking freed memeory\n");
    for(i = 0; i < indexAllocedStorage; i++){   
        if(pAllocedStorage[i] != (size_t)NULL){
            printf( "Memory leak %X\n", (unsigned int)pAllocedStorage[i]);
            free((void *)pAllocedStorage[i]);
        }
    }

    free(pAllocedStorage);
    pAllocedStorage = NULL;
}

I would use rmalloc. It is a simple library (actually it is only two files) to debug memory usage, but it also has support for statistics. Since you already wrapper functions it should be very easy to use rmalloc for it. Keep in mind that you also need to replace strdup, etc.

Your program may also need to intercept realloc(), calloc(), getcwd() (as it may allocate memory when buffer is NULL in some implementations) and maybe strdup() or a similar function, if it is supported by your compiler

If you are running on x86 you could just run your binary under valgrind and it would gather all this information for you, using the standard implementation of malloc and free. Simple.

I've been trying out some of the same techniques mentioned on this page and wound up here from a google search. I know this question is old, but wanted to add for the record...

1) Does your operating system not provide any tools to see how much heap memory is in use in a running process? I see you're talking about ARM, so this may well be the case. In most full-featured OSes, this is just a matter of using a cmd-line tool to see the heap size.

2) If available in your libc, sbrk(0) on most platforms will tell you the end address of your data segment. If you have it, all you need to do is store that address at the start of your program (say, startBrk=sbrk(0)), then at any time your allocated size is sbrk(0) - startBrk.

3) If shared objects can be used, you're dynamically linking to your libc, and your OS's runtime loader has something like an LD_PRELOAD environment variable, you might find it more useful to build your own shared object that defines the actual libc functions with the same symbols (malloc(), not MemAlloc()), then have the loader load your lib first and "interpose" the libc functions. You can further obtain the addresses of the actual libc functions with dlsym() and the RTLD_NEXT flag so you can do what you are doing above without having to recompile all your code to use your malloc/free wrappers. It is then just a runtime decision when you start your program (or any program that fits the description in the first sentence) where you set an environment variable like LD_PRELOAD=mymemdebug.so and then run it. (google for shared object interposition.. it's a great technique and one used by many debuggers/profilers)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top