FlatBuffers与ProtoBuf内存模型
ProtoBuf
Protobuf的整体格式
以二进制流的方式存储,按照定义的字段顺序紧紧相邻。每个字段对应有key-value
数据相邻,key由field_number和wire_type计算出,value由该字段定义的值(可能包括value长度)组成。
Varint数字表示方法
Varint 是一种紧凑的表示数字的方法。
它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。比如对于 int32 类型的数字,一般需要 4 个 byte 来表示。但是采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。当然凡事都有好的也有不好的一面,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。
Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。
proto buffer中的各种数据表示方法
无符号整数: Base 128 Varints
小于 128 的数字都可以用一个 byte 表示。大于 128 的数字,比如 128,会用2个字节表示
有符号整数: zigzag 编码
一个负数一般会被表示为一个很大的整数,因为计算机定义负数的符号位为数字的最高位。如果采用 Varint 表示一个负数,那么一定需要 5 个 byte。为此 Google Protocol Buffer 定义了 sint32、sint64 这种有符号类型,采用 zigzag 编码。下面会重点介绍。
其他的数据类型
比如字符串等,用一个 varint 表示长度,然后将其余部分紧跟在这个长度部分之后即可。
注意的是字符串的存储并不会压缩空间。
FlatBuffers
FlatBuffers数据存储结构
FlatBuffers底层使用了java的
ByteBuffer
进行数据存储,ByteBuffer可以算是java NIO体系中的重要成员,很多jvm单独为它从heap中划分了一块存储区域进行数据存储,这样就避免了java数据到native层的传输需要经过java heap到native heap的数据拷贝过程,从而提高了数据读写的效率。
但是ByteBuffer是针对直接进行数据存取操作的,虽然它提供了诸如asIntBuffer等方法来构造包装类以便针对int等类型的数据进行读取,但是毕竟FlatBuffers存储的一般并不是单一的数据类型,因此如果让用户来直接操作底层的ByteBuffer的话还是非常麻烦的。
幸运的是FlatBuffersBuilder已经为我们封装了很多操作。
FlatBuffers对ByteBuffer的基本使用原则
- 小端模式
FlatBuffers对各种基本数据的存储都是按照小端模式来进行的,因为这种模式目前和大部分处理器的存储模式是一致的,可以加快数据读写的数据。这一点FlatBuffers一般是在初始化ByteBuffer的时候调用ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)来实现的。 - 写入数据方向和读取数据方向不同
和一般向ByteBuffer写入数据的习惯不同,FlatBuffers向ByteBuffer中写入数据的顺序是从ByteBuffer的尾部向头部填充,由于这种增长方向和ByteBuffer默认的增长方向不同,因此FlatBuffers在向ByteBuffer中写入数据的时候就不能依赖ByteBuffer的position来标记有效数据位置,而是自己维护了一个space变量来指明有效数据的位置,在分析FlatBuffersBuilder的时候要特别注意这个变量的增长特点。但是,和数据的写入方向不同的是,FlatBuffers从ByteBuffer中解析数据的时候又是按照ByteBuffer正常的顺序来进行的。FlatBuffers这样组织数据存储的好处是,在从左到右解析数据的时候,能够保证最先读取到的就是整个ByteBuffer的概要信息(例如Table类型的vtable字段),方便解析。如下图所示:
关于结论
FB在访问数据时不需要创建临时内存,每个数据的存储位置可以认为是指定好的,直接读取内存就可实现反序列化,不需要复杂的解析逻辑,因此省去了很多中间对象的创建、内存申请;
PB是K-V存储方式,每个数据存放的先后顺序及位置是不能预知的,因此需要遍历过程去完成数据的解析,然后包装对应到对象,比FB多了解析过程。
参考:
[Android FlatBuffers剖析]
[ProtocolBuffers的编码]
[移动场景下通信协议FlatBuffers、ProtocolBuffers、MessagePack选优]
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 using1174@foxmail.com
文章标题: FlatBuffers与ProtoBuf内存模型
文章字数: 1,236
本文作者: Jun
发布时间: 2018-07-28, 17:12:00
最后更新: 2018-07-28, 17:33:47
原始链接: http://yoursite.com/2018/07/28/FlatBuffers与ProtoBuf内存模型/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。