协议缓冲区数组中浪费的字节数?

Mar*_*tin 3 c# protocol-buffers protobuf-net

我有一个像这样的协议缓冲区设置:

[ProtoContract]
Foo
{
    [ProtoMember(1)]
    Bar[] Bars;
}
Run Code Online (Sandbox Code Playgroud)

单个Bar被编码为67字节的协议缓冲区.这听起来是正确的,因为我知道Bar几乎只是一个64字节的数组,然后有3个字节的开销用于长度前缀.

但是,当我使用20 Bars的数组编码Foo时,需要1362个字节.20*67是1340,所以只有22个字节的开销用于编码数组!

为什么这会占用这么多空间?我能做些什么来减少它吗?

Mar*_*ell 5

这个开销很简单,它需要知道20个对象中每个对象的开始和结束位置.在不破坏格式的情况下,我可以做任何不同的事情(即做一些违反规范的事情).

如果你真的想要血淋淋的细节:

数组或列表(如果我们排除"打包",这里不适用)只是重复的子消息块.有两种布局可用于子消息; 字符串和组.使用字符串,布局为:

[header][length][data]
Run Code Online (Sandbox Code Playgroud)

其中header是wire-type和field-number的varint编码的mash(在这种情况下为字段1的十六进制08),length是varint编码的大小data,data是子对象本身.对于小对象(data小于128个字节),这通常意味着每个对象有2个字节的开销,具体取决于:字段编号(15以上的字段占用更多空间),b:数据的大小.

对于一个组,布局是:

[header][data][footer]
Run Code Online (Sandbox Code Playgroud)

其中header是wire-type和field-number的varint编码的mash(在这种情况下为字段1,data为十六进制0B),是子对象,footer是另一个varint mash,用于指示对象的结尾(此处为hex 0C)字段1)的情况.

群体通常不那么受欢迎,但它们具有的优点是,data随着大小的增加它们不会产生任何开销.对于小的字段数(小于16),开销是每个对象2个字节.当然,您需要为大字段数支付双倍的费用.