简单的C实现跟踪内存malloc / free?

编程语言:C平台:ARM编译器:ADS 1.2

我需要在项目中跟踪简单的melloc/free通话。 我只需要了解程序分配了所有资源后需要多少堆内存的基本概念。 因此,我为malloc/free调用提供了一个包装器。 在这些包装器中,我需要在调用malloc时增加当前内存计数,并在调用free时减少它。 malloc案例是直截了当的,因为我有从调用者分配的大小。 我想知道如何处理free案例,因为我需要在某处存储指针/大小映射。 这是C,我没有标准的地图来轻松实现这一点。

我试图避免在任何库中链接,所以更喜欢* .c / h实现。

所以我想知道是否已经有一个简单的实现可能会引导我。 如果没有,这是继续实施的动机。

编辑:纯粹用于调试,此代码不随产品提供。

编辑:根据Makis的回答进行初步实施。 我很感激对此的反馈。

编辑:重新实施

 #include  #include  #include  #include  #include  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 buffer[i] = i; mybuffer->bools[i] = true; bufferinfo->whichbuffer = (unsigned int)(i/100); } MemFree(bufferinfo); MemFree(mybuffer); if(pCh) { MemFree(pCh); } return EXIT_SUCCESS; } 

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

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

要么您可以访问malloc / free使用的内部表(请参阅此问题: 在哪里执行malloc()/ free()存储已分配的大小和地址?以获取某些提示),或者您必须在包装器中管理自己的表。

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

编辑:我错过了这是针对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; } 

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

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

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

我一直在试用本页提到的一些相同的技术,并从谷歌搜索结束。 我知道这个问题很老了,但是想加入记录…

1)您的操作系统是否没有提供任何工具来查看正在运行的进程中正在使用多少堆内存? 我看到你在谈论ARM,所以情况可能就是如此。 在大多数function齐全的操作系统中,只需使用cmd-line工具查看堆大小即可。

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

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