C++ 内存泄漏排查:从裸 new 到 RAII 修复,附 ASan 实战
背景
机器人感知节点里,每帧点云、IMU 数据都要分配缓冲。
如果用了裸 new 但忘了 delete,跑几小时内存就持续上涨。
最终节点被 OOM 杀掉,线上排查只能看 RSS 曲线。
本文用一个最小例子,演示泄漏怎么产生、怎么用 ASan 定位、怎么用现代 C++ 修掉。
反面教材:最经典的泄漏
#include <iostream>
#include <string>
void ProcessPointCloud(const std::string& sensor_id) {
// 预处理缓冲:运行时才知道大小,必须 new
int* buffer = new int[1024];
// 模拟处理
buffer[0] = 42;
std::cout << " [" << sensor_id << "] 处理完成" << std::endl;
// 忘记 delete[] buffer; <– 泄漏点
}
int main() {
std::cout << "=== 触发内存泄漏 ===" << std::endl;
for (int i = 0; i < 3; ++i) {
ProcessPointCloud("Lidar_" + std::to_string(i));
}
std::cout << "程序结束,ASan 会报告泄漏详情。" << std::endl;
return 0;
}
编译运行:
g++ -std=c++17 -fsanitize=address -g exercise2_leak.cpp -o exercise2_leak && ./exercise2_leak
ASan 会直接打印泄漏报告,定位到 new int[1024] 那一行。
修复版:两种现代写法
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 修复方式一:用 vector 管理动态数组
void ProcessPointCloudVector(const std::string& sensor_id) {
std::vector<int> buffer(1024);
buffer[0] = 42;
std::cout << " [" << sensor_id << "] vector 版处理完成" << std::endl;
}
// 修复方式二:用 unique_ptr 管理动态数组
void ProcessPointCloudUnique(const std::string& sensor_id) {
auto buffer = std::make_unique<int[]>(1024);
buffer[0] = 42;
std::cout << " [" << sensor_id << "] unique_ptr 版处理完成" << std::endl;
}
int main() {
std::cout << "=== 修复后:无泄漏 ===" << std::endl;
for (int i = 0; i < 3; ++i) {
ProcessPointCloudVector("Lidar_" + std::to_string(i));
}
for (int i = 0; i < 3; ++i) {
ProcessPointCloudUnique("Lidar_" + std::to_string(i));
}
std::cout << "程序结束,ASan 报告干净。" << std::endl;
return 0;
}
编译运行:
g++ -std=c++17 -fsanitize=address -g exercise2_fixed.cpp -o exercise2_fixed && ./exercise2_fixed
跑完 ASan 报告是干净的,零泄漏。
现代 C++ 内存管理规则
| 普通对象 | std::make_unique<T>() / std::make_shared<T>() |
| 动态数组 | std::vector<T> |
| 独占资源 | std::unique_ptr<T> |
| 共享资源 | std::shared_ptr<T> |
| 观察资源 | std::weak_ptr<T> |
| 对象池 / 对齐内存 | 内部用 placement new,外层 RAII |
| 与 C 接口交互 | 裸指针进,RAII 包装出 |
结论
业务层不写裸 new/delete。
底层或性能敏感场景会用,但必须被 RAII 包起来。
排查流程:复现 → 加 -fsanitize=address 重编 → 跑一遍看报告 → 修掉 → 再跑一遍确认归零。
网硕互联帮助中心


评论前必须登录!
注册