使用protobuf-net,是否可以在不分配内存的情况下反序列化消息?

6
我有一个C#应用程序,需要每秒反序列化成千上万个protobuf消息。为了避免不必要的垃圾回收,我想知道是否有一种使用预分配内存的方法,使得每个反序列化操作都不需要分配新内存。
我的设想是,在执行之前分配一个消息对象池,并指示protobuf代码使用此池中的下一个可用消息进行每次反序列化。
这种功能是否存在,或者在这种情况下是否有其他优化内存使用的方法?
谢谢!

2
你确定这确实是一个问题吗?你是否遇到过这种情况,即你的应用程序由于垃圾回收而内存不足或运行缓慢? - BFree
不,但这是当前需要分配内存的高频组件中唯一的代码区域,因此如果有简单的方法可以消除它,那么探索消除它的可能性对我来说似乎是值得的。 - newdayrising
短生命周期对象的分配和垃圾回收非常快速。除非实际分析了代码并发现这是瓶颈,否则您可能不需要担心这个问题。 - svick
对于某些人来说,极快的速度可能是一个问题。我有一款软件定期测试大约110亿条记录的一组文件,并且应该尽可能快地完成此操作。每天增加约5亿条记录。 - TomTom
1个回答

11

是的,有一个!内部已经使用了一个微型池来避免分配过多的工作缓冲区,但如果您正在处理足够多的对象以至于GC成为问题,您可以使用自己的分配方案,并创建一个自定义对象工厂;目前不能在属性中指定这个对象工厂,但可以通过类型模型应用:

RuntimeTypeModel.Default.Add(typeof (Foo), true).SetFactory(factory);

其中factory可以是:

  • Foo上的一个static方法的名称(例如"CreateFoo"),该方法返回一个Foo
  • 任何返回一个Foostatic方法的MethodInfo(不必在Foo上)

在这两种情况下,方法可以使用与回调相同的签名-因此它可以是无参数的,也可以接受上下文信息。例如:

public static Foo CreateFoo() {
    return GetFromYourOwnMicroPool();
}

注意,在这种用法中,期望工厂将对象重置为原始状态; protobuf-net 将不会尝试执行此操作。请注意,目前 protobuf-net 不公开其微型池作为可重复使用的组件,但您可以轻松地重新使用源代码。

此功能是专门添加以支持具有非常高吞吐量的用户,他希望消除即使最微小的 GC 开销(基于大量的测量...他们向我发送了漂亮的图表和一切 ;p)

另外:除了根对象以外,protobuf-net 支持 struct 值而不需要装箱;因此,如果您拥有一个复杂/嵌套的对象模型,则在极端情况下,另一个选项是查看 structs。


请问您能否澄清如何使用结构体?我们可以在从proto文件生成时这样做吗?Github自述文件中的这个声明怎么样?“该代码假定类型将在选定成员周围是可变的。因此,不支持自定义结构体,因为它们应该是不可变的。” - Aranda
@Aranda 这个评论可能是在结构体支持之前发表的。生成工具目前只会生成类,但结构体应该可以正常工作。 - Marc Gravell
谢谢Marc。我通过手动编辑生成的类为结构体(对于非根类型)使其工作,但无法消除所有分配,因为工厂方法和合并方法似乎都不能消除根类型的分配。我们现在正在试用Flatbuffers。 - Aranda
有人有上述概念的可行示例吗? - rollsch
1
@rolls 我几乎可以肯定地帮忙,但这是一个非常老的问题;也许值得在 GitHub 上创建一个新的问题,明确你想要做什么。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接