Rapidjson使用方式不当导致的内存泄漏问题

       上次有个项目中要用到rapidjson生成json格式的数据文档,由于第一次用rapidjson,中间出现了疑似内存泄漏的问题,具体现象就是程序占用的内存不断在增加,debug过程中发现只要用rapidjson生成json数据后,内存占用就会增长,于是问题定位到rapidjson。由于是开源库,所以不觉得是库内部导致的内存泄漏,那么极有可能就是用法不当导致的,经过一番试验,最后找到了具体的原因。

       先贴上测试的代码,下面再进行分析:

#include <iostream>
#include <string>
#include <unistd.h>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>

using namespace std;
using namespace rapidjson;

Document *doc;

int func(Document * document)
{
    string cont_str1 = to_string(time(NULL));
    string cont_str2 = to_string(time(NULL)+100);
	
    /* 获取rapidjson内存分配器,这里因为需求原因,是通过全局变量doc获取的分配器,
     * 这是最关键的地方,只要doc不释放,这个分配器分配出来的内存也就不会释放。
     */
    Document d(kObjectType);
    Document::AllocatorType& allocator = document->GetAllocator();
	
    /* 插入数据 */
    Value val(kStringType);
    val.SetString(cont_str1.c_str(), allocator);
    d.AddMember("string1", val, allocator);
	
    val.SetString(cont_str2.c_str(), allocator);
    d.AddMember("string2", val, allocator);

    document->PushBack(d, allocator);

    return 0;
}

int doc_print(Document * document)
{
    StringBuffer buffer;
    Writer<StringBuffer> writer(buffer);
	
    document->Accept(writer);
    cout << buffer.GetString() << endl;
}

int main(void)
{
    doc = new Document;
    doc->SetArray();
	
    /* 往doc中连续插入数据,持续时间为20s */
    for (int i = 0; i < 4000; ++i)
    {
        func(doc);
        usleep(50000);
    }
	
    /* 将json数据打印出来。同时需要注意的是,退出doc_print()函数后buffer才会释放 */
    doc_print(doc);

    /* 用完之后要释放doc,如果不释放,之前在fun()中使用分配器分配的内存将不会自动回收 */
    delete doc;
    doc = NULL;
    sleep(20);

    return 0;
}

       代码大概的流程就是先定义一个Document根节点,然后不断插入数据,持续20秒,之后将数据打印出来,然后释放根节点,最后sleep20秒,退出程序。这里的时间设置是为了能观察内存的使用情况。

       根节点是一个全局的指针变量,之所以是全局的,是因为项目的需求是会不定时生成json数据,但是每隔一段(固定的)时间才会将这些数据统一写入json文件。如果是生成json数据的同时就写入文件,那么Document根节点用局部变量就可以了,就不会有内存泄漏的问题。

      内存不断增长的原因和rapidjson的分配器有关,因为这里分配器是获取根节点的,只要根节点不释放,那么用分配器分配出来的内存是不会自动释放的。所以该程序的内存消耗情况应该是这样的:前20秒一直在使用分配器分配内存,所以程序占用内存应该会一直增加;在打印完数据后就释放了根节点,那么之前分配器分配的内存也就随之释放掉了,此时占用内存应该会将下来。运行一下程序,同时看下程序的占用内存情况,验证下我们的猜想:

       结果:占用内存确实在不断上升,从1068上升到2124,在释放根节点后,内存就降下来了。所以使用完分配器后,要记得释放相应的Document。

      另外,打印时调用的doc_print()函数中定义了一个StringBuffer类型的局部变量buffer,buffer也是要等到退出该函数之后(即生命周期结束后),才会自动释放。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值