2011-03-06 55 views
3

我有一个协议缓冲设置是这样的:协议缓冲区数组中的字节浪费?

[ProtoContract] 
Foo 
{ 
    [ProtoMember(1)] 
    Bar[] Bars; 
} 

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

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

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

+1

和Foo本身是免费的吗?它应该占用一些空间吗? – user492238 2011-03-06 17:07:56

+0

它应该占用一些空间,但22个字节是一个很大的空间! – Martin 2011-03-06 17:16:30

+2

在1340之上的22个字节不是'那么多',当然不是用于序列化。继续你的生活吧。 – 2011-03-06 18:32:34

回答

5

这个开销是很简单,它需要知道其中每个20个对象的开始和结束的信息。在不破坏格式的情况下,我可以做任何不同的事情(即做与规范相反的事情)。

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

数组或列表(如果我们排除“包装”,它在这里不适用),只需子消息的重复块。有两种布局可用于子消息;字符串和组。用字符串,布局:

[header][length][data] 

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

随着一组,布局:

[header][data][footer] 

其中header是线型和场数(在这种情况下,与场1十六进制0B)的varint编码醪,data是子对象,并且footer是另一个varint mash,用于指示对象的结尾(在此例中为字段1的十六进制0C)。

团体普遍不太受欢迎,但他们的优势是他们不会招致任何开销,因为data的规模增长。对于小的字段号(小于16),开销是每个对象2字节。当然,你需要支付大型现场数字的两倍。

+0

谢谢马克,我怀疑这可能是我遇到的协议中的一个恶毒案件。 – Martin 2011-03-07 01:40:33

2

默认情况下,数组实际上并不是作为数组传递的,而是作为重复的成员传递的,这些成员的开销略高一些。

所以我想你实际上有1字节的开销每个重复的数组元素,加上2额外的字节开销顶部。

您可以通过使用“packed”数组来减少开销。 protobuf网支持这样的:http://code.google.com/p/protobuf-net/

为二进制格式的文档是在这里:http://code.google.com/apis/protocolbuffers/docs/encoding.html

+0

奇数,在数组上使用打包会触发一个异常“打包缓冲区不支持wire-type:String”。这很奇怪,因为酒吧不是一个字符串! – Martin 2011-03-06 18:01:39

+1

@马丁 - 就protobuf规范而言:是的。这只是特定布局的名称 - 它不代表* text *字符串。对象有两种可能的格式;字符串和组。 Packed确实可以消除头文件的开销,但只适用于非常基本的类型,例如整数和浮点数;不是对象。 – 2011-03-06 22:57:59