Простая реализация C для отслеживания памяти malloc / free? - PullRequest
10 голосов
/ 12 мая 2009

язык программирования: C платформа: ARM Компилятор: ADS 1.2

Мне нужно отслеживать простые melloc/free звонки в моем проекте. Мне просто нужно получить очень общее представление о том, сколько кучи памяти требуется, когда программа распределяет все свои ресурсы. Поэтому я предоставил оболочку для вызовов malloc/free. В этих оболочках мне нужно увеличить текущий счетчик памяти при вызове malloc и уменьшить его при вызове free. Случай malloc прост, так как у меня есть размер, выделяемый вызывающей стороной. Мне интересно, как поступить со случаем free, так как мне нужно где-то хранить отображение указателя / размера. Это C, у меня нет стандартной карты, чтобы легко это реализовать.

Я стараюсь избегать ссылок в любых библиотеках, поэтому предпочел бы реализацию * .c / h.

Так что мне интересно, есть ли уже простая реализация, к которой я могу привести. Если нет, то это мотивация пойти дальше и реализовать его.

РЕДАКТИРОВАТЬ: чисто для отладки, и этот код не поставляется с продуктом.

РЕДАКТИРОВАТЬ: Первоначальная реализация на основе ответа от Makis. Буду признателен за отзыв об этом.

РЕДАКТИРОВАТЬ: переработанная реализация

#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;
}

Ответы [ 7 ]

12 голосов
/ 12 мая 2009

Вы можете выделить несколько дополнительных байтов в вашей обёртке и указать либо идентификатор (если вы хотите соединить malloc () и free ()), либо просто размер там. Просто используйте malloc () намного больше памяти, сохраните информацию в начале вашего блока памяти и переместите указатель, на который вы вернетесь, на столько байтов вперед.

Кстати, это также легко можно использовать для указателей / отпечатков пальцев и тому подобного.

2 голосов
/ 12 мая 2009

Либо вы можете иметь доступ к внутренним таблицам, используемым malloc / free (см. Этот вопрос: Где malloc () / free () хранит выделенные размеры и адреса? для некоторых подсказок) или вы должны управлять своими собственными таблицами в своих оболочках.

1 голос
/ 12 мая 2009

Вы всегда можете использовать valgrind вместо того, чтобы использовать собственную реализацию. Если вас не волнует объем выделяемой памяти, вы можете использовать еще более простую реализацию: (Я сделал это очень быстро, поэтому могут возникнуть ошибки, и я понимаю, что это не самая эффективная реализация. первоначальный размер и увеличение на некоторый фактор для изменения размера и т. д., но вы поняли.)

РЕДАКТИРОВАТЬ: Я пропустил, что это было для ARM, насколько мне известно, valgrind недоступен на ARM, поэтому это может быть не вариант.

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;
}
0 голосов
/ 02 августа 2013

Я пробовал некоторые из тех же методов, упомянутых на этой странице, и попал сюда из поиска Google. Я знаю, что этот вопрос старый, но хотел добавить для записи ...

1) Разве ваша операционная система не предоставляет каких-либо инструментов, чтобы увидеть, сколько кучи памяти используется в работающем процессе? Я вижу, вы говорите об ARM, так что это вполне может иметь место. В большинстве полнофункциональных ОС это просто вопрос использования инструмента cmd-line для просмотра размера кучи.

2) Если доступно на вашем libc, sbrk (0) на большинстве платформ сообщит вам конечный адрес вашего сегмента данных. Если он у вас есть, все, что вам нужно сделать, это сохранить этот адрес в начале вашей программы (скажем, startBrk = sbrk (0)), тогда в любой момент ваш выделенный размер будет sbrk (0) - startBrk.

3) Если можно использовать общие объекты, вы динамически связываетесь с вашим libc, а загрузчик времени выполнения вашей ОС имеет что-то вроде переменной среды LD_PRELOAD, вы можете найти более полезным создать свой собственный общий объект, который определяет реальный Функции libc с теми же символами (malloc (), а не MemAlloc ()), затем загрузчик сначала загружает вашу lib и «вставляет» функции libc. Кроме того, вы можете получить адреса реальных функций libc с помощью dlsym () и флага RTLD_NEXT, чтобы вы могли делать то, что вы делаете выше, без необходимости перекомпилировать весь ваш код для использования ваших оболочек malloc / free. Тогда это просто решение времени выполнения, когда вы запускаете свою программу (или любую программу, которая соответствует описанию в первом предложении), где вы устанавливаете переменную среды, такую ​​как LD_PRELOAD = mymemdebug.so, а затем запускаете ее. (Google для вставки общих объектов. Это отличный метод, который используется многими отладчиками / профилировщиками)

0 голосов
/ 13 мая 2009

Если вы работаете на x86, вы можете просто запустить свой двоичный файл под valgrind , и он соберет всю эту информацию для вас, используя стандартную реализацию malloc и free. Простой.

0 голосов
/ 12 мая 2009

Ваша программа может также нуждаться в перехвате realloc (), calloc (), getcwd () (поскольку она может выделять память, когда буфер равен NULL в некоторых реализациях) и, возможно, strdup () или аналогичной функции, если она поддерживается ваш компилятор

0 голосов
/ 12 мая 2009

Я бы использовал rmalloc . Это простая библиотека (на самом деле это всего два файла) для отладки использования памяти, но она также поддерживает статистику. Поскольку у вас уже есть функции-обертки, для него должно быть очень легко использовать rmalloc. Имейте в виду, что вам также необходимо заменить strdup и т. Д.

...