使用 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"
)上返回Foo
的static
方法的名称
返回Foo
的任何static
方法的MethodInfo
(不需要在Foo
上)
在任何一种情况下,该方法都可以使用与回调相同的签名——因此它可以是无参数的,或者可以接受上下文信息。例如:
public static Foo CreateFoo()
return GetFromYourOwnMicroPool();
请注意,在此用法中,工厂 会将对象重置为原始状态; protobuf-net 不会尝试这样做。另请注意,目前 protobuf-net 并未将其微池公开为可重用组件,但您可以轻松地重用源代码。
此功能是专门为支持吞吐量非常高的用户而添加的,他们希望消除哪怕是最轻微的 GC 开销(基于大量测量...他们向我发送了漂亮的图表和所有内容;p)
另外:除了根对象,protobuf-net 支持struct
值而无需装箱;所以如果你有一个复杂/嵌套的对象模型,另一个选择在极端情况下是查看struct
s。
【讨论】:
你能解释一下如何使用结构吗?从 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 的 ASP.NET SessionState 模式 SQLServer 序列化
如何以编程方式确定类型是不是可以通过 protobuf-net 本地序列化?