protobuf - 使用arena构建proto对象

参考资料:

[1] C++ Arena Allocation Guide:https://developers.google.cn/protocol-buffers/docs/reference/arenas#arenaclass

[2] arena.h的文档:https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.arena#Arena.SpaceUsed.details

[3] proto源码中arena的单元测试源码:https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/arena_unittest.cc

 

什么是Arena

        Arena是一个c++-only的特性,可以优化proto创建过程中对内存的使用。内存的分配和回收是很消耗CPU时间的,在默认情况下,protobuf对每一个message对象、每一个子对象、某几种类型的field(例如stirng、bytes),都是为其在堆上分配内存。在创建一个新的message对象的时候,就会出现很多次在堆上的内存分配,析构message的时候也会出现很多次堆上的内存释放。Arena就是针对这种大量的堆上内存分配和释放做出的一种优化措施。Arena与一片预分配的内存相关联,当新的对象使用arena来构建新的proto对象时,新的对象就生成在arena的这一片预分配的内存上,而不是对其中每一个需要分配内存的部分都单独去堆上申请一块内存来用。用Arena来构造对象还能提供可观的cache相关的性能改进,当读取一个message对象时,它的数据更可能分布在连续的一段内存空间上,因此遍历消息中的数据时更可能命中cache。(参考[1])

 

如何使用Arena

首先需要在.proto文件中加上下面这行,使得proto在生成.cc和.h文件的时候,能够为其中的message类定义出Arena相关的函数。

option cc_enable_arenas = true;

在代码中如下使用(来自[1]):

#include 

Arena arena;
MyMessage* arena_message =
   google::protobuf::Arena::CreateMessage(&arena);

这样就是使用Arena来构造proto message对象的用法。arena_message这个指针指向的空间不需要手动delete,这块内存是由Arena来管理的。只要Arena对象存在,这个指针就是有效的。

 

如果想自己手动分配一块内存,然后让Arena使用这块内存,就需要配合ArenaOptions(下面代码来自[3],ArenaOptions的定义可以参考[2])来使用:

std::vector arena_block(128 * 1024);
ArenaOptions options;
options.initial_block = &arena_block[0];
options.initial_block_size = arena_block.size();
Arena arena(options);
MyMessage* message = Arena::CreateMessage(&arena);

不是所有的字段都会分配在Arena的内存中

根据文档所述,string字段仍然会分配在堆上,不使用Arena的内存。另外我试了一下bytes类型,也是分配在堆上的。如果field类型是另一个message,只有这个message的定义proto文档里使用了option cc_enable_arenas = true;才会将其分配在Arena上(参考embedded_message)

 

 

 

 

 

 

 

你可能感兴趣的:(C++,proto)