答案是手写内存泄漏检测器可通过重载malloc和free记录内存分配信息。1. 重载内存分配函数,记录每次malloc/new和free/delete的调用堆栈与大小;2. 程序结束时输出未释放的内存块地址、大小及分配位置,实现简单检测。

在C++开发中,内存泄漏是常见问题。虽然有Valgrind、AddressSanitizer等强大工具,但在某些嵌入式环境或需要轻量级方案时,手写一个简单的内存泄漏检测器很有价值。下面介绍如何实现一个基础但实用的内存泄漏检测工具。
原理与设计思路
核心思想是在程序运行期间记录每一次malloc和free(或new和)操作,通过重载内存管理函数,在调用前后插入日志记录逻辑。程序退出前输出未释放的内存块信息。
主要功能包括:
- 拦截new/操作
- 记录分配地址、大小、调用位置(文件名、行号)
- 程序结束时打印未释放的内存
重载 new 和 delete 操作符
在全局作用域中重载operator new和,可以捕获所有使用new和的内存操作。
立即学习“C++免费学习笔记(深入)”;
#include#include #include
定义宏简化使用
直接写new(file, line)语法不合法,需要用宏替换new表达式。
#define new new(__FILE__, __LINE__)
这样所有使用new的地方都会自动带上文件名和行号。注意这个宏会影响整个翻译单元,建议只在测试构建中启用。
示例代码:
int main() {
int* p1 = new int(42); // 被捕获
int* p2 = new int[100]; // 注意:数组版本需额外重载
delete[] p2; // 正常释放
// delete p1; // 故意漏掉,制造泄漏
// 程序结束前输出泄漏
for (const auto& alloc : g_allocations) {
printf("Leak: %p, size=%zu, at %s:%d\n",
alloc.first, alloc.second.size,
alloc.second.file, alloc.second.line);
}
return 0;}
运行后会输出类似:
Leak: 0x7f9a80c00000, size=4, at main.cpp:20支持数组 new/delete[]
上面例子中new int[100]不会被拦截,因为调用了。需要补充重载:
void* operator new[](size_t size, const char* file, int line) {
void* ptr = std::malloc(size);
if (ptr) {
g_allocations[ptr] = {size, file, line};
}
return ptr;
}
void* operator new[](size_t size) {
return ::operator new[](size, "unknown", 0);
}
void operator delete[](void* ptr) noexcept {
::operator delete(ptr);
}
注意:标准允许为空实现,实际调用的是普通,所以复用已有逻辑即可。
注意事项与局限性
这个检测器适用于开发调试阶段,有几点需要注意:
- 仅捕获new/,不处理(可类似扩展)
- 宏替换可能影响第三方库代码,建议封装头文件并控制作用范围
- 多线程环境下需加锁保护
- 不能检测越界、重复释放等其他内存错误
基本上就这些。不复杂但容易忽略细节。适合集成到小型项目或学习内存管理机制。









