目
注释等价无, 你是什么感受. 为我们多留条后路, 多写注释.
好 看测试代码 main.c
#include <stdio.h>
#include <stdlib.h>
#include "checkmem.h"
/*
* 演示一种检测内存越界的办法
* 添加上下限方式
*/
int main(int argc, char* argv[]) {
// 实验步骤是, 是申请内存, 在操作内存
char* as = mc_malloc(16);
mc_check(as);
// 内存越界了
//as[16] = 18;
//mc_check(as);
// 重新分配内存, 再次越界
as = mc_realloc(as, 15);
as[15] = 44;
mc_check(as);
free(as);
return 0;
}
测试结果
到这里内存越界的思路和实现都已经完毕了.欢迎思考尝试.
正文 - 内存全局监测
内存全局检测思路更简单. 采用引用'计数方式'处理. 扯一点很多自动垃圾回收机制都采用了引用计数方式.
包括内核层例如 文件描述符, IPC 共享内存, 消息机制等. 先看接口 memglobal.h
#ifndef _H_MEMGLOBAL_MEMGLOBAL
#define _H_MEMGLOBAL_MEMGLOBAL
#include <stddef.h>
#include <stdlib.h>
/*
* 全局启动内存简单监测
*/
extern inline void mg_start(void);
/*
* 增加的全局计数的 malloc
* sz : 待分配内存大小
* : 返回分配的内存首地址
*/
extern void* mg_malloc(size_t sz);
/*
* 增加了全局计数的 calloc
* sc : 分配的个数
* sz : 每个分配大小
* : 返回分配内存的首地址
*/
extern inline void* mg_calloc(size_t sc, size_t sz);
/*
* 增加了计数的 realloc
* ptr : 上一次分配的内存地址
* sz : 待重新分配的内存大小
* : 返回重新分配好的内存地址
*/
extern void* mg_realloc(void* ptr, size_t sz);
/*
* 增加了计数处理的内存 free
* ptr : 上面函数返回地址的指针
*/
extern inline void mg_free(void* ptr);
// 在测试模式下开启 全局内存使用计数
#if defined(_DEBUG)
# define malloc mg_malloc
# define calloc mg_calloc
# define realloc mg_realloc
# define free mg_free
#else
# define malloc malloc
# define calloc calloc
# define realloc realloc
# define free free
#endif
#endif // !_H_MEMGLOBAL_MEMGLOBAL
还是比较优美的. 再看 memglobal.c
#include "memglobal.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
// 取消内置宏, 防止递归
#undef malloc
#undef calloc
#undef realloc
#undef free
// 控制台打印错误信息, fmt必须是双引号括起来的宏
#define IOERR(io, fmt, ...) \
fprintf(io,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\
__FILE__, __func__, __LINE__, errno, strerror(errno), ##__VA_ARGS__)
// 全局内存计数, 系统第一次构造的时候为0
static int _mct;
#define _STR_MGTXT "checkmem.log"
// mg内存监测退出时候, 记录一些信息
static void _mg_exit(void) {
if (_mct == 0) return;
// 先打印信息到控制台
IOERR(stderr, "Detect memory leaks _mct = %d!!", _mct);
//输出到文件
FILE* txt = fopen(_STR_MGTXT, "a");
if (txt == NULL) {
IOERR(stderr, "fopen " _STR_MGTXT " a is error!");
return;
}
IOERR(txt, "Detect memory leaks _mct = %d!!", _mct);
fclose(txt);
}
/*
* 全局启动内存简单监测
*/
inline void
mg_start(void) {
// 注册退出监测事件
atexit(_mg_exit);
}
/*
* 增加的全局计数的 malloc
* sz : 待分配内存大小
* : 返回分配的内存首地址
*/
void*
mg_malloc(size_t sz) {
void* ptr = malloc(sz);
if (!ptr) return NULL;
++_mct;
memset(ptr, 0x00, sz);
return ptr;
}
/*
* 增加了全局计数的 calloc
* sc : 分配的个数
* sz : 每个分配大小
* : 返回分配内存的首地址
*/
inline void*
mg_calloc(size_t sc, size_t sz) {
return mg_malloc(sc*sz);
}
/*
* 增加了计数的 realloc
* ptr : 上一次分配的内存地址
* sz : 待重新分配的内存大小
* : 返回重新分配好的内存地址
*/
void*
mg_realloc(void* ptr, size_t sz) {
if (!ptr) return mg_malloc(sz);
return realloc(ptr, sz);
}
/*
* 增加了计数处理的内存 free
* ptr : 上面函数返回地址的指针
*/
inline void
mg_free(void* ptr) {
if (!ptr) return;
--_mct;
free(ptr);
}
中间用了
// 取消内置宏, 防止递归
#undef malloc
#undef calloc