1.protobuf对象是如何释放(数组)内存的?
毫无疑问是,通过调用析构函数。只要让protobuf定义的对象调用析构函数,无论嵌套了多少层数据、包含了多少个数组都可以释放new出来的内存。
2.protobuf对象Clear()接口和STL容器中的clear()接口的有何区别?
我们习惯使用STL模板中各类容器(vector,map,set),而不用考虑底层对内存的使用。无论装在容器中的数据如何复杂如何庞大,只要能执行clear()就可以一了百了。
但是,相同情况用到protobuf却不尽然。protobuf对象的Clear()操作,只是反复调用memset执行内存重置为0的操作,这就好比将电脑C盘格式化,但C盘的容量并没有改变。
3.protobuf对象作为成员变量,如何释放内存?
考虑一种情况:protobuf对象作为成员变量,一直存在内存使用(增删改),也需要对它进行周期性清空操作(调用Clear()接口实现内存重置为0)。如何在清空操作的同时释放所占用的内存的空间?
答:借助共享指针shared_ptr的reset()接口。
举例说明:
protobuf协议定义如下,ConfigItem里面包含一个SubItem数组,在测试例子中调用ConfigItem中add_items() 填充1000条数据。
package proto;
message SubItem
{
required int32 id = 1;
required int32 type = 2;
required int32 value = 3;
}
message ConfigItem
{
repeated SubItem items = 1;
}
测试C++代码:
#include<memory>
#include"client.pb.h"
using std::shared_ptr;
void readCfg_verson1()
{
proto::ConfigItem config;
for ( int idx = 0; idx < 1000; idx++ )
{
auto item = config.add_items();
item->set_id(idx);
item->set_type(idx);
item->set_value(idx);
}
}
void readCfg_version2()
{
proto::ConfigItem *pconfig = new proto::ConfigItem;
for ( int idx = 0; idx < 1000; idx++ )
{
auto item = pconfig->add_items();
item->set_id(idx);
item->set_type(idx);
item->set_value(idx);
}
delete pconfig;
}
class Foo
{
public:
Foo():pconfig_(new proto::ConfigItem){}
shared_ptr<proto::ConfigItem> pconfig_;
void readCfg_version3()
{
for ( int idx = 0; idx < 1000; idx++ )
{
auto item = pconfig_->add_items();
item->set_id(idx);
item->set_type(idx);
item->set_value(idx);
}
}
};
int main(void)
{
//1.protobuf对象作为栈对象自动析构
readCfg_verson1();
//2.protobuf对象堆对象使用delete手动析构
readCfg_version2();
//3.protobuf对象作为成员变量借用shared_ptr的reset()接口调用析构函数
Foo foo;
foo.readCfg_version3();
//千万注意:使用protobuf自带的Clear()函数,相当于对C数组进行memset操作,跟STL容器的clear()接口作用不一样,将内存重置为0并没有释放所占用的堆内存空间。
foo.config_->Clear();
//正确做法://借助智能指针shared_ptr的reset()接口,析构老对象并释放所占内存,同时重新创建一个新对象(只占用一个指针的内存)。
proom->pconfig_.reset(new proto::ConfigItem);
//todo ...
return 0;
}