使用 fastDDS 遇到的内存泄漏问题

文章讲述了在使用fastDDS时,由于对void*指针的不当管理导致内存泄漏的问题。作者最初误以为reader->type().create_data()创建的是智能指针,后来发现需要手动调用delete_data()释放内存。为了解决这个问题,作者建议使用智能指针和泛型技术,确保对象在不再使用时能自动释放,提高代码的优雅性和可维护性。
摘要由CSDN通过智能技术生成

主要结论
使用 void * prt = reader->type().create_data(); 创建的 void * 指针,需要通过 reader->type().delete_data(prt); 来释放,否则会出现内存泄漏问题

起初为了方便开发者编写业务代码,我写了几个基于 fastDDS 的封装类,大大提高了开发效率。

但是在压测时,发现长时间运行程序,程序的VmRSS 不断增长。判断可能是内存泄露。

于是开始调查,从业务代码到库代码,将返回指针换成智能指针,排查每个 new 等等,但始终没找到彻底解决的方法。

这时怀疑是不是 DDS 本身收发信息出了问题。便搭建了简易的测试项目,惊奇地发现没有出现泄露问题。经过细致对比,才发现之前写的封装类有问题。

因为之前要解决各种泛型问题,我使用了 void * 作为参数或者返回值。而在封装类内部需要创建一个消息实体指针,因为不知道消息对象类型,采用了用 reader.type().createData() 方法来创建消息对象。当初理解该方法创建的是智能指针,会自动释放,就没有太在意,也没特别考虑释放问题。

而后面使用中,又将其用 void * 的方式将其返回出了代码作用域,从而造成了问题。

修改方法很简单,假设消息对象指针是 msgprt,在使用完成消息对象之后调用 reader.type().deleteData(msgprt) 即可。修正了相关代码,测试没有再发现泄露问题。

代码如下:

// MySubscriber 是对 fastDDS Subscriber 类的分装类
void MySubscriber::SubListener::on_data_available(DataReader *reader) {
    void *st_ = reader->type().create_data();  // 通过 reader 创建一个内存区域 用于暂存消息
    SampleInfo info_;
    if (reader->take_next_sample(st_, &info_) == ReturnCode_t::RETCODE_OK) {
        if (info_.valid_data) {
            if (on_data_ != nullptr) { // on_data_ 是收到消息后的业务层回调函数
                on_data_(st_);  // 将数据传送出去
            }
        }
    }
    // 这里是重点,当没有获得消息或者业务层回调函数处理完后 释放掉于用暂存消息的内存
    reader->type().delete_data(st_);  
}

但这并非最好的解决方法,因为 如果消息对象作为返回值,出了代码作用域后,必须要求调用者自行执行释放代码。这样一是不方便,不优雅,二是会给项目带来开发和维护上的风险。

更好的解决方法是,采用泛型和智能指针技术,这样可以在内部创建消息对象的智能指针,并在返回时移交给调用者;调用者用智能指针接收返回值,当调用者的代码区域执行完成后,对象会自动释放,从而解决了上面的两个隐忧。

虽然写法上比用 void * 稍微啰嗦了些,但是很值得的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值