C++ 内存泄漏:ASAN 工具 超详细使用教程
AddressSanitizer(ASAN) 是 C++ 排查内存泄漏的工具,比 Valgrind 快 5~10 倍,GCC/Clang/VS 全都自带,不用额外安装,直接编译就能用。
它能精准检测:
- 内存泄漏(malloc/new 没 free/delete)
- 堆溢出、栈溢出
- 野指针、重复释放
- 使用已释放内存
一、1 分钟快速上手(直接复制用)
1. 编译命令
GCC / Clang 编译时加一个参数:
bash
# 必加:-fsanitize=address
g++ -g -fsanitize=address main.cpp -o test
运行程序:
bash
./test
程序退出时,ASAN 会自动打印泄漏位置 + 代码行号。
二、完整示例:检测出泄漏
测试代码(故意写内存泄漏)
cpp
#include <iostream>
using namespace std;
void test_leak() {
// 堆上申请内存,没有 delete → 泄漏
int* arr = new int[100];
}
int main() {
test_leak();
return 0;
}
编译 + 运行
bash
g++ -g -fsanitize=address main.cpp -o test
./test
ASAN 直接输出泄漏结果
ERROR: LeakSanitizer: detected memory leaks
Direct leak of 400 byte(s) in 1 object(s) allocated from:
#0 operator new[](unsigned long) (libasan.so+...)
#1 test_leak() main.cpp:6
#2 main main.cpp:10
直接告诉你:
- 哪一行泄漏:
main.cpp 第 6 行 - 泄漏大小:
400 字节 - 哪个函数:
test_leak()
三、ASAN 常用编译参数(必记)
1. 基础必用(检测泄漏+越界)
bash
g++ -g -fsanitize=address test.cpp -o test
-g:保留调试信息(必须加,否则不显示行号)-fsanitize=address:开启 ASAN
2. 只检测内存泄漏(更快)
bash
# 只检查泄漏,不检查越界/野指针
g++ -g -fsanitize=leak test.cpp -o test
3. 关闭泄漏检查(只查越界)
bash
export ASAN_OPTIONS=detect_leaks=0
./test
四、Windows VS 使用 ASAN
VS 2019 及以上原生支持,不用装插件:
- 右键项目 → 属性
- C/C++ → 常规 → 启用地址消毒剂 → 选择 是 (/fsanitize=address)
- 重新编译运行
- 输出窗口直接显示泄漏行号
五、ASAN 泄漏报告怎么看?
报告结构非常清晰:
ERROR: LeakSanitizer: detected memory leaks
Direct leak of 400 byte(s) in 1 object(s) allocated from:
#0 operator new[](unsigned long)
#1 test_leak() main.cpp:6 <-- 泄漏代码行
#2 main main.cpp:10
重点看:
Direct leak:直接泄漏byte(s):泄漏大小main.cpp:6:精确到行号- 调用栈:谁申请了没释放
六、C++ 最常见的泄漏场景(ASAN 一键查出)
1. new 没 delete / new\[\] 没 delete\[\]
cpp
int* p = new int;
// 没 delete p; → 泄漏
2. 容器/指针忘记释放
cpp
vector<int*> vec;
vec.push_back(new int);
// 程序结束没遍历 delete → 泄漏
3. 类中指针没在析构函数释放
cpp
class A {
int* p;
public:
A() { p = new int; }
// ~A() { delete p; } 析构函数忘写 → 泄漏
};
4. 函数内申请内存,没有返回也没有释放
cpp
void func() {
char* buf = new char[1024];
// 没释放,直接退出 → 泄漏
}
七、注意事项
-
ASAN 会增加内存占用(约 2x),性能下降约 2 倍
→ 只用于测试/调试 ,不要上线生产环境。 -
必须加
-g编译,才能显示行号。 -
多线程程序也能正常检测。
-
有些库(如第三方静态库)没开 ASAN,可能出现误报,可用:
bashexport ASAN_OPTIONS=detect_leaks=0
总结
- C++ 排查内存泄漏首选 ASAN,自带能准确定位到行号。
- 编译只需要加:
-g -fsanitize=address。 - 运行程序,退出后自动打印泄漏报告。
- 能查:泄漏、越界、野指针、重复释放。
你只要把你的代码用这个参数重新编译运行,就能立刻看到所有内存泄漏位置。