云计算百科
云计算领域专业知识百科平台

C++ 内存泄漏排查:从裸 new 到 RAII 修复,附 ASan 实战

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 重编 → 跑一遍看报告 → 修掉 → 再跑一遍确认归零。

赞(0)
未经允许不得转载:网硕互联帮助中心 » C++ 内存泄漏排查:从裸 new 到 RAII 修复,附 ASan 实战
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!