Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple C implementation to track memory malloc/free?

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;
}
like image 497
dubnde Avatar asked May 12 '09 10:05

dubnde


3 Answers

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.

like image 146
Makis Avatar answered Oct 14 '22 02:10

Makis


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.

like image 2
mouviciel Avatar answered Oct 14 '22 02:10

mouviciel


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;
}
like image 1
Sweeney Avatar answered Oct 14 '22 03:10

Sweeney