如何最小化 Protobuf.NET 内存消耗

Posted

技术标签:

【中文标题】如何最小化 Protobuf.NET 内存消耗【英文标题】:How to minimize Protobuf.NET memory consumption 【发布时间】:2011-10-25 16:07:07 【问题描述】:

我正在使用 Protobuf.NET 序列化大量类,其中大部分作为引用(因为我的数据结构中有多个对相同类的引用)。

所有序列化的类都通过使用 ImplicitFirends.AllFields 进行序列化,以确保 一切都被倾倒了。

在我当前的测试用例中,我有 53 个文件,总和为 500MB。

当我使用 Protobuf.NET 反序列化器读取此数据时,我的私有字节/常驻内存会飙升至 9GB 并停留在那里(即,这不是在反序列化后释放/GC 的临时内存)。

另一个奇怪的事情是,如果我重写(重新序列化)所有数据,它仍然保持相同的大小。

这个 x20 在内存中爆炸有意义吗?

【问题讨论】:

【参考方案1】:

我将运行一些测试,但它听起来就像是它为避免分配而保留的缓冲池。除了测试之外,我将在下一个版本中添加一个“转储池”方法(并禁用?)。其实想一想:我会把这些改成WeakReference,这样它们就可以在它们存在的时候被重新使用,但仍然被收集起来。

您可能还会发现(作为合同的一个选项)对子对象和列表使用“组”编码可以大大减少这里的内容; length-prefixed 是默认值(也是 Google 的首选选项),但组的写入效率更高,因为它们可以直接写入而无需任何缓冲。让我知道你是否想要一个这样的例子。 Protobuf-net 的设计使得它们之间的切换不是一个重大变化,但 other protobuf 客户端不会那么宽容,如果您使用 protobuf 与其他系统进行互操作,那就更棘手了。

【讨论】:

我不确定这真的是缓冲池。当我转储堆时,我看到了多个(即 10,000 或更多)类实例,这些实例应该在个位数范围内。有没有办法验证 AsReference “功能”是否真的有效?我有一个特定的类被设置为被编码为 AsReference,我实际上应该有其中之一,但我似乎有超过 10,000 个......这让我怀疑 AsReference 功能...... @damageboy 从您的数据中验证肯定很容易 - 只需调用 ReferenceEquals。如果您可以展示您的场景的一个小示例,这将有所帮助,请注意,引用仅在单个图形操作期间有效 - 如果您分别调用 Deserialize 5 次,仍然是 5 个对象,而不是一个。是这里的情景吗?我是这样的,可能还有其他选项(包括我多年来一直想要实现的核心 .NET 引用交换接口,它可能允许你做你想做的事)。 我想我正在解决这个问题...如果我有一个继承方案,其中 C 派生自 B,而 B 派生自 A...是否应该将所有这些类标记为参考? 嗨,Marc,我的情况似乎有些复杂。我用“AsReference”标记的一些类确实被序列化为引用并通过了 ReferenceEquals 测试,而其他更复杂的类,可能具有继承的那些类不,并且基本上被复制......在有关的场景中支持 AsReference子类型和继承? @damageboy 应该是,但这很复杂。我必须测试。

以上是关于如何最小化 Protobuf.NET 内存消耗的主要内容,如果未能解决你的问题,请参考以下文章

(22)如何优化内存使用

Protobuf.net 内存使用情况

STM32L051从进入停止模式,达到最小电流消耗的时间

java 进程消耗内存只增不减

[模拟] aw3770. 最小消耗(模拟+aw周赛008_1)

5548. 最小体力消耗路径 二分