init
This commit is contained in:
commit
06c458e859
194
leak_detector_c.c
Normal file
194
leak_detector_c.c
Normal file
@ -0,0 +1,194 @@
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include "leak_detector_c.h"
|
||||
|
||||
// 取消宏定义,使用原始 malloc/calloc/free
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
#undef free
|
||||
|
||||
// 全局链表起始与当前位置指针
|
||||
static MEM_LEAK *ptr_start = NULL;
|
||||
static MEM_LEAK *ptr_next = NULL;
|
||||
|
||||
/*
|
||||
* 将分配的内存信息添加到链表中
|
||||
*/
|
||||
void add(MEM_INFO alloc_info)
|
||||
{
|
||||
MEM_LEAK *mem_leak_info = NULL;
|
||||
|
||||
// 分配一个新的链表节点
|
||||
mem_leak_info = (MEM_LEAK *) malloc(sizeof(MEM_LEAK));
|
||||
mem_leak_info->mem_info.address = alloc_info.address;
|
||||
mem_leak_info->mem_info.size = alloc_info.size;
|
||||
strcpy(mem_leak_info->mem_info.file_name, alloc_info.file_name);
|
||||
mem_leak_info->mem_info.line = alloc_info.line;
|
||||
mem_leak_info->next = NULL;
|
||||
|
||||
// 如果是第一个节点
|
||||
if (ptr_start == NULL) {
|
||||
ptr_start = mem_leak_info;
|
||||
ptr_next = ptr_start;
|
||||
} else {
|
||||
// 添加到链表末尾
|
||||
ptr_next->next = mem_leak_info;
|
||||
ptr_next = ptr_next->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 根据位置索引从链表中删除内存记录
|
||||
*/
|
||||
void erase(unsigned pos)
|
||||
{
|
||||
unsigned index = 0;
|
||||
MEM_LEAK *alloc_info, *temp;
|
||||
|
||||
// 删除第一个节点
|
||||
if (pos == 0) {
|
||||
MEM_LEAK *temp = ptr_start;
|
||||
ptr_start = ptr_start->next;
|
||||
free(temp);
|
||||
} else {
|
||||
// 删除中间或最后一个节点
|
||||
for (index = 0, alloc_info = ptr_start; index < pos; alloc_info = alloc_info->next, ++index) {
|
||||
if (pos == index + 1) {
|
||||
temp = alloc_info->next;
|
||||
alloc_info->next = temp->next;
|
||||
free(temp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 清空链表中所有内存记录
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
MEM_LEAK *temp = ptr_start;
|
||||
MEM_LEAK *alloc_info = ptr_start;
|
||||
|
||||
while (alloc_info != NULL) {
|
||||
alloc_info = alloc_info->next;
|
||||
free(temp);
|
||||
temp = alloc_info;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 自定义 malloc 函数:分配内存并记录来源信息
|
||||
*/
|
||||
void *xmalloc(unsigned int size, const char *file, unsigned int line)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if (ptr != NULL) {
|
||||
add_mem_info(ptr, size, file, line);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* 自定义 calloc 函数:分配并初始化内存,同时记录信息
|
||||
*/
|
||||
void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line)
|
||||
{
|
||||
unsigned total_size;
|
||||
void *ptr = calloc(elements, size);
|
||||
if (ptr != NULL) {
|
||||
total_size = elements * size;
|
||||
add_mem_info(ptr, total_size, file, line);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* 自定义 free 函数:释放内存前先移除记录
|
||||
*/
|
||||
void xfree(void *mem_ref)
|
||||
{
|
||||
remove_mem_info(mem_ref); // 移除记录
|
||||
free(mem_ref); // 实际释放
|
||||
}
|
||||
|
||||
/*
|
||||
* 创建内存分配信息并添加到链表中
|
||||
*/
|
||||
void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line)
|
||||
{
|
||||
MEM_INFO mem_alloc_info;
|
||||
|
||||
// 清空结构体,确保初始化干净
|
||||
memset(&mem_alloc_info, 0, sizeof(mem_alloc_info));
|
||||
mem_alloc_info.address = mem_ref;
|
||||
mem_alloc_info.size = size;
|
||||
strncpy(mem_alloc_info.file_name, file, FILE_NAME_LENGTH);
|
||||
mem_alloc_info.line = line;
|
||||
|
||||
// 添加到链表中
|
||||
add(mem_alloc_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* 从链表中移除某段已释放的内存记录
|
||||
*/
|
||||
void remove_mem_info(void *mem_ref)
|
||||
{
|
||||
unsigned short index;
|
||||
MEM_LEAK *leak_info = ptr_start;
|
||||
|
||||
// 遍历链表查找目标地址
|
||||
for (index = 0; leak_info != NULL; ++index, leak_info = leak_info->next) {
|
||||
if (leak_info->mem_info.address == mem_ref) {
|
||||
erase(index); // 找到后删除
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 将所有未释放的内存信息写入输出文件
|
||||
*/
|
||||
void report_mem_leak(void)
|
||||
{
|
||||
MEM_LEAK *leak_info;
|
||||
FILE *fp_write = fopen(OUTPUT_FILE, "wt");
|
||||
|
||||
if (fp_write != NULL) {
|
||||
fprintf(fp_write, "Memory Leak Summary\n");
|
||||
fprintf(fp_write, "-----------------------------------\n");
|
||||
|
||||
// 遍历所有未释放的记录,写入文件
|
||||
for (leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
|
||||
fprintf(fp_write, "address : %p\n", leak_info->mem_info.address);
|
||||
fprintf(fp_write, "size : %d bytes\n", leak_info->mem_info.size);
|
||||
fprintf(fp_write, "file : %s\n", leak_info->mem_info.file_name);
|
||||
fprintf(fp_write, "line : %d\n", leak_info->mem_info.line);
|
||||
fprintf(fp_write, "-----------------------------------\n");
|
||||
}
|
||||
|
||||
fclose(fp_write); // 关闭输出文件
|
||||
}
|
||||
|
||||
clear(); // 清空链表,释放资源
|
||||
}
|
||||
|
||||
|
||||
void dump_mem_leak(void)
|
||||
{
|
||||
MEM_LEAK *leak_info;
|
||||
|
||||
fprintf(stderr, "Memory Leak Snapshot\n");
|
||||
fprintf(stderr, "-----------------------------------\n");
|
||||
|
||||
for (leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
|
||||
fprintf(stderr, "address : %p\n", leak_info->mem_info.address);
|
||||
fprintf(stderr, "size : %d bytes\n", leak_info->mem_info.size);
|
||||
fprintf(stderr, "file : %s\n", leak_info->mem_info.file_name);
|
||||
fprintf(stderr, "line : %d\n", leak_info->mem_info.line);
|
||||
fprintf(stderr, "-----------------------------------\n");
|
||||
}
|
||||
}
|
61
leak_detector_c.h
Normal file
61
leak_detector_c.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef LEAK_DETECTOR_C_H
|
||||
#define LEAK_DETECTOR_C_H
|
||||
|
||||
// 文件名最大长度
|
||||
#define FILE_NAME_LENGTH 256
|
||||
|
||||
// 内存泄漏信息输出文件
|
||||
#define OUTPUT_FILE "leak_info.txt"
|
||||
|
||||
// 用宏重定义 malloc、calloc 和 free,为其添加文件名和行号信息
|
||||
#define malloc(size) xmalloc (size, __FILE__, __LINE__)
|
||||
#define calloc(elements, size) xcalloc (elements, size, __FILE__, __LINE__)
|
||||
#define free(mem_ref) xfree(mem_ref)
|
||||
|
||||
// 用于记录每一次内存分配的信息结构体
|
||||
struct _MEM_INFO {
|
||||
void *address; // 分配的内存地址
|
||||
unsigned int size; // 分配的大小
|
||||
char file_name[FILE_NAME_LENGTH]; // 分配发生的文件名
|
||||
unsigned int line; // 分配发生的代码行号
|
||||
};
|
||||
typedef struct _MEM_INFO MEM_INFO;
|
||||
|
||||
// 内存泄漏记录结构体,使用链表形式组织
|
||||
struct _MEM_LEAK {
|
||||
MEM_INFO mem_info; // 内存信息
|
||||
struct _MEM_LEAK *next; // 指向下一个节点的指针
|
||||
};
|
||||
|
||||
typedef struct _MEM_LEAK MEM_LEAK;
|
||||
|
||||
// 添加一条内存分配信息记录
|
||||
void add(MEM_INFO alloc_info);
|
||||
|
||||
// 删除某个位置的内存记录
|
||||
void erase(unsigned pos);
|
||||
|
||||
// 清空所有内存记录
|
||||
void clear(void);
|
||||
|
||||
// 自定义 malloc:记录内存分配位置
|
||||
void *xmalloc(unsigned int size, const char *file, unsigned int line);
|
||||
|
||||
// 自定义 calloc:记录内存分配位置
|
||||
void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line);
|
||||
|
||||
// 自定义 free:在释放内存时移除记录
|
||||
void xfree(void *mem_ref);
|
||||
|
||||
// 添加一条内存分配记录
|
||||
void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line);
|
||||
|
||||
// 移除某个内存记录(在调用 free 时使用)
|
||||
void remove_mem_info(void *mem_ref);
|
||||
|
||||
// 生成内存泄漏报告
|
||||
extern void report_mem_leak(void);
|
||||
|
||||
extern void dump_mem_leak(void);
|
||||
|
||||
#endif
|
12
leak_info.txt
Normal file
12
leak_info.txt
Normal file
@ -0,0 +1,12 @@
|
||||
Memory Leak Summary
|
||||
-----------------------------------
|
||||
address : 0x7fffe6d502a0
|
||||
size : 1 bytes
|
||||
file : test.c
|
||||
line : 8
|
||||
-----------------------------------
|
||||
address : 0x7fffe6d50520
|
||||
size : 60 bytes
|
||||
file : test.c
|
||||
line : 14
|
||||
-----------------------------------
|
20
test.c
Normal file
20
test.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include "leak_detector_c.h"
|
||||
int main()
|
||||
{
|
||||
atexit(report_mem_leak);
|
||||
|
||||
char *ptr1 = (char *)malloc(1);
|
||||
|
||||
|
||||
|
||||
|
||||
int *ptr2 = (int *)calloc(1, sizeof(int));
|
||||
float * ptr3 = (float *) calloc(15, sizeof(float));
|
||||
free(ptr2);
|
||||
|
||||
dump_mem_leak();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user