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

Posted

技术标签:

【中文标题】使用 protobuf-net,是不是可以在不分配内存的情况下反序列化消息?【英文标题】:Using protobuf-net, is it possible to deserialize a message without allocating memory?使用 protobuf-net,是否可以在不分配内存的情况下反序列化消息? 【发布时间】:2012-01-16 18:08:47 【问题描述】:

我有一个 C# 应用程序,它需要每秒反序列化数千条 protobuf 消息。为了避免不必要的垃圾收集,我想知道是否有一种方法可以使用预分配的内存,这样每个反序列化操作就不需要分配新的内存。

我的设想是在执行之前分配一个消息对象池,然后指示 protobuf 代码使用该池中的下一个可用消息进行每次反序列化。

是否存在此功能,或者在这种情况下是否有其他方法可以优化内存使用?

谢谢!

【问题讨论】:

您确定这实际上是一个问题吗?您是否遇到过应用程序内存不足或由于垃圾回收而运行缓慢的情况? 不,但这是当前需要分配内存的高频组件中唯一的代码区域,因此对我来说探索消除它的可能性似乎是值得的,特别是如果有这样做的直接方法。 短期对象的分配和垃圾回收非常快。除非您真正分析您的代码并发现这是瓶颈,否则您可能不应该担心这一点。 对于某些人来说,速度极快是个问题。我有一个软件可以定期测试一组包含大约 110 亿个条目的文件 - 并且应该尽可能快地测试。每天增加大约 5 亿条条目。 【参考方案1】:

是的,有!在内部,它已经使用了一个微池来避免分配太多的工作缓冲区,但是如果你通过了足够多的对象,GC 是一个问题,你也许可以使用你自己的分配方案,并创建一个自定义对象工厂;这目前无法在 attributes 上指定,但可以通过 type-model 应用:

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

其中factory 是:

Foo(即"CreateFoo")上返回Foostatic 方法的名称 返回Foo 的任何static 方法的MethodInfo(不需要在Foo 上)

在任何一种情况下,该方法都可以使用与回调相同的签名——因此它可以是无参数的,或者可以接受上下文信息。例如:

public static Foo CreateFoo() 
    return GetFromYourOwnMicroPool();

请注意,在此用法中,工厂 会将对象重置为原始状态; protobuf-net 不会尝试这样做。另请注意,目前 protobuf-net 并未将其微池公开为可重用组件,但您可以轻松地重用源代码。

此功能是专门为支持吞吐量非常高的用户而添加的,他们希望消除哪怕是最轻微的 GC 开销(基于大量测量...他们向我发送了漂亮的图表和所有内容;p)

另外:除了根对象,protobuf-net 支持struct 值而无需装箱;所以如果你有一个复杂/嵌套的对象模型,另一个选择在极端情况下是查看structs。

【讨论】:

你能解释一下如何使用结构吗?从 proto 文件生成时我们可以这样做吗? github自述文件上的这个声明怎么样? The code assumes that types will be mutable around the elected members. Accordingly, custom structs are not supported, since they should be immutable. @Aranda 这句话可能早于对结构的支持。生成工具目前只发出类,但结构应该可以正常工作。 谢谢马克。我确实通过手动将生成的类编辑为结构(对于非根类型)来使其工作,但无法消除所有分配,因为工厂方法和合并方法似乎都没有消除根类型的分配。我们目前正在尝试切换到 Flatbuffers。 有人有上述概念的工作示例吗? @rolls 我几乎肯定可以提供帮助,但这是一个非常古老的问题;可能值得在 GitHub 上创建一个新问题,明确说明您要做什么。

以上是关于使用 protobuf-net,是不是可以在不分配内存的情况下反序列化消息?的主要内容,如果未能解决你的问题,请参考以下文章

我可以重复使用对象实例来避免使用 protobuf-net 进行分配吗?

Protobuf-net 对字节数组进行序列化/反序列化

使用 protobuf-net 的 ASP.NET SessionState 模式 SQLServer 序列化

如何以编程方式确定类型是不是可以通过 protobuf-net 本地序列化?

<T> 在运行时 ProtoBuf-net 模型中是不是允许?

使用成员编号保存文档,而不是使用 protobuf-net 和 MongoDB 的名称