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

本文以机器人感知节点中的点云和IMU数据缓冲分配为背景,通过最小示例演示裸new导致内存泄漏的典型问题,利用AddressSanitizer(ASan)精准定位泄漏点,并对比两种基于RAII的现代修复方案(如std::unique_ptr)。强调业务层禁用裸new/delete,底层需封装于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 重编 → 跑一遍看报告 → 修掉 → 再跑一遍确认归零。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HAPPY酷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值