11

编程语言: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;
}
4

7 回答 7

13

您可以在包装器中分配一些额外的字节,并在其中放置一个 id(如果您希望能够耦合 malloc() 和 free())或只是其中的大小。只需 malloc() 更多的内存,将信息存储在内存块的开头,然后将返回的指针向前移动那么多字节。

顺便说一句,这也可以很容易地用于栅栏指针/指纹等。

于 2009-05-12T10:29:30.860 回答
2

要么您可以访问malloc/使用的内部表free(请参阅这个问题:Where Do malloc() / free() Store Allocated Sizes and Addresses?以获得一些提示),或者您必须在包装器中管理自己的表。

于 2009-05-12T10:23:07.110 回答
1

你总是可以使用valgrind而不是滚动你自己的实现。如果您不关心分配的内存量,则可以使用更简单的实现:(我这样做的速度非常快,因此可能会出现错误,并且我意识到这不是最有效的实现。应该给 pAllocedStorage 一个初始大小并增加一些因素以调整大小等,但你明白了。)

编辑:我错过了这是针对 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;
}
于 2009-05-12T12:17:50.133 回答
0

我会使用rmalloc。它是一个简单的库(实际上只有两个文件)来调试内存使用情况,但它也支持统计信息。由于您已经包装了函数,因此使用 rmalloc 应该很容易。请记住,您还需要替换 strdup 等。

于 2009-05-12T12:34:07.030 回答
0

您的程序可能还需要拦截 realloc()、calloc()、getcwd()(因为在某些实现中,当 buffer 为 NULL 时它可能会分配内存)以及 strdup() 或类似函数,如果您的编译器支持的话

于 2009-05-12T13:12:28.287 回答
0

如果你正在运行,x86你可以在valgrind下运行你的二进制malloc文件,它会使用和的标准实现为你收集所有这些信息free。简单的。

于 2009-05-13T03:38:17.893 回答
0

我一直在尝试这个页面上提到的一些相同的技术,并从谷歌搜索到这里。我知道这个问题很老,但想添加记录......

1) 您的操作系统是否没有提供任何工具来查看正在运行的进程中使用了多少堆内存?我看到你在谈论 ARM,所以很可能就是这种情况。在大多数功能齐全的操作系统中,这只是使用命令行工具查看堆大小的问题。

2) 如果在您的 libc 中可用,大多数平台上的 sbrk(0) 会告诉您数据段的结束地址。如果你有它,你需要做的就是在你的程序开始时存储那个地址(比如,startBrk=sbrk(0)),那么在任何时候你分配的大小都是 sbrk(0) - startBrk。

3)如果可以使用共享对象,您正在动态链接到您的 libc,并且您的操作系统的运行时加载程序具有类似 LD_PRELOAD 环境变量的东西,您可能会发现构建自己的定义实际 libc 函数的共享对象更有用相同的符号(malloc(),而不是 MemAlloc()),然后让加载程序首先加载您的 lib 并“插入”libc 函数。您可以使用 dlsym() 和 RTLD_NEXT 标志进一步获取实际 libc 函数的地址,这样您就可以执行上述操作,而无需重新编译所有代码以使用 malloc/free 包装器。然后,当您启动程序(或任何符合第一句话中描述的程序)时,它只是一个运行时决定,您在其中设置了一个环境变量,如 LD_PRELOAD=mymemdebug.so 然后运行它。

于 2013-08-01T20:04:17.267 回答