获取动态内存使用
说明
内存动态分配是指在程序运行过程中,根据程序的需要动态地分配内存空间,以便存储数据或创建对象。内存动态分配通常使用指针来实现,通过调用系统提供的内存分配函数(如malloc、calloc等)来申请内存空间,申请成功后,返回一个指向该内存空间的指针,进而在程序中使用该指针来访问分配的内存空间。
内存动态分配的优点是可以动态地分配内存空间,避免浪费,提高内存使用效率。同时,动态分配的内存空间也可以随着程序的需求进行动态的释放,避免内存泄漏和出错。但是,使用内存动态分配也存在一些缺点,如容易出现内存泄漏、空间碎片等问题,需要程序员具有一定的技巧和注意事项才能正确、高效地使用内存动态分配。
这里,介绍一种可以检查动态内存使用情况的小工具valloc
,以便统计动态内存的使用情况,以及检查是否有空间碎片忘记释放。用其方法代替的内存分配方法,可以计算动态内存使用的情况。
源码
源文件valloc.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static int count = 0;
static int use = 0;
void* v_malloc(size_t size)
{
void* p;
p = malloc(size ? size + sizeof(int) : 0);
if (!p) return NULL;
count++;
*(int*)p = size;
use += size;
return (void*)((char*)p + sizeof(int));
}
void* v_calloc(size_t num, size_t size)
{
void* p;
p = v_malloc(num * size);
if (!p) return NULL;
memset(p, 0, num * size);
return p;
}
void v_free(void* block)
{
void* p;
if (!block) return;
p = (void*)((char*)block - sizeof(int));
use -= *(int*)p;
count--;
free(p);
}
void* v_realloc(void* block, size_t size)
{
void* p;
int s = 0;
if (block)
{
block = (void*)((char*)block - sizeof(int));
s = *(int*)block;
}
p = realloc(block, size ? size + sizeof(int) : 0);
if (!p) return NULL;
if (!block) count++;
*(int*)p = size;
use += (size - s);
return (void*)((char*)p + sizeof(int));
}
int v_mcheck(int *_count, int *_use)
{
if (_count) *_count = count;
if (_use) *_use = use;
// if (count || use)
// {
// printf("|||----------->>> area = %d, size = %d\r\n", count, use);
// return 1;
// }
return 0;
}
头文件 valloc.h
/*********************************************************************************************************
* ------------------------------------------------------------------------------------------------------
* file description
* ------------------------------------------------------------------------------------------------------
* \file valloc.h
* \unit valloc
* \brief Test how much space is allocated
* \author Lamdonn
* \details v1.0.0
********************************************************************************************************/
#ifndef __valloc_H
#define __valloc_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdlib.h>
void* v_malloc(size_t size);
void* v_calloc(size_t num, size_t size);
void v_free(void* block);
void* v_realloc(void* block, size_t size);
int v_mcheck(int *_count, int *_use);
#define malloc v_malloc
#define calloc v_calloc
#define free v_free
#define realloc v_realloc
#ifdef __cplusplus
}
#endif
#endif
原理
比如分配 num 大小的空间
| <— sizeof(int) —> | <------- num -------> |
| _________________ | ________________ |
- 调用原版
malloc
函数分配sizeof(int)+num
大小的空间 - 前面
sizeof(int)
大小的空间作为int
型记录该片空间的大小num
- 增加记录分配次数到模块静态变量
count
,增加记录分配空间大小到模块静态变use
- 返回原分配地址向后偏移
sizeof(int)
后的地址给用户作为新的分配地址
同样,在释放内存时候
- 先把释放的地址向前偏移
sizeof(int)
得到实际的分配地址 - 实际地址的前
sizeof(int)
空间记录了该片空间的大小,模块静态变量count
和use
相应缩减 - 调用原版
free
函数释放实际的分配地址
然后,调用int v_mcheck(int *_count, int *_use);
方法获取模块静态变量count
和use
即可得知动态内存的使用情况了
在头文件中增加了以下的宏定义
#define malloc v_malloc
#define calloc v_calloc
#define free v_free
#define realloc v_realloc
在需要统计动态内存的源文件文件中,只需添加valloc
头文件进来,原版的malloc
、free
等函数则会被同名宏定义替换成v_malloc
、v_free
等带v_
前缀的函数,而无需改动其他代码。
例子
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
malloc(12);
return 0;
}
像上面这种情况,我们分配了内存,如果不释放代码一复杂就很难发现内存没有释放。
加入valloc
工具
#include <stdio.h>
#include <stdlib.h>
#include "src/valloc.h"
int main(int argc, char *argv[])
{
int area = 0, use = 0;
malloc(12);
v_mcheck(&area, &use);
if (area || use)
{
printf("|||----------->>> area = %d, size = %d\r\n", area, use);
}
return 0;
}
添加valloc
头文件,该头文件宏定义会覆盖替代malloc
、free
等函数,从而不用改动其他代码,然后在结束的地方调用v_mcheck
方法检查动态内存使用情况。
结果,没有释放的内存就报出来了,有1片空间没释放用了12大小的内存。
|||----------->>> area = 1, size = 12
小结
在需要测量动态内存使用的文件中简单的包含头文件而无需改动其他代码,然后在需要测量内存使用的地方调用v_mcheck
方法检查动态内存使用情况。不需检查动态内存后,把头文件包含移除了即可。