Protobuf.net内存使用情况

时间:2011-12-09 18:44:00

标签: c# protobuf-net

Heyup。 protobuf.net的长期爱好者。

快速提问。我有一个高度多线程的C#应用​​程序,可以反序列化大约100个对象/秒,大约50MB /秒。我看到非常大的内存使用量,远远超过我正在反序列化的内存。我通过'Red Gate ANTS Memory Profiler'运行应用程序,由于protobuf(超过50%的应用程序使用),它向我展示了大量的第2代内存对象。大多数对象都是int值,并与以下内容链接:

- TypeModel.TryDeserializeList()
- ProtoBuf.Meta.BasicList

任何有助于减少第二代内存使用的帮助都将受到赞赏。

马克

2 个答案:

答案 0 :(得分:5)

听起来我这里的根T是数组本身,即

int[] values = Serializer.Deserialize<int[]>(source);

如果是这种情况,那么当前它会为该场景使用略微次优的路径(原因是:使用相同的代码路径,即使是具有弱元编程/反射模型的平台,例如iOS)。我会尝试花几个小时整理一下,但在回答你的问题时 - 你应该能够通过添加一个父对象来避免这个问题:

[ProtoContract]
public class MyDataWrapper { // need a new name...
    [ProtoMember(1)]
    public int[] Values { get;set; }
}

然后:

int[] values = Serializer.Deserialize<MyDataWrapper>(source).Values;

这实际上与已通过Serialize<int[]>序列化的数据完全兼容,只要使用的字段编号为1即可。这种方法的另一个好处是,如果需要,你可以使用“压缩”子格式(仅适用于诸如int的基元列表/数组);虽然在这种情况下可能仍然不是一个好主意,因为它的长度很长(在序列化时可能需要缓冲)。


附加背景; “v1”这里基本上使用MakeGenericType在运行中切换到类似上面的内容;然而,由于这种方法在“v2”目标的许多其他平台中不可用,因此它在这里采用了不太优雅的方法。但是现在它非常稳定,我可以在完整的.NET 2.0或更高版本上运行时重新添加优化版本。

答案 1 :(得分:1)

详细说明Marcs的回答我做了一个快速的

基准测试
  • 使用包装器进行序列化/反序列化与使用数组。
  • 启用/不启用服务器GC

基准测试创建了100.000个复杂对象(1个跨度,2个双倍,2个整数,2个整数,0到4个短元素(1个字符)的字符串列表)并重复序列化/反序列化过程30次并测量运行期间所花费的总时间和GC集合的数量。结果是(在VS之外的Release中运行)

GC IsServer: False, GC latency: Interactive, GC LOH compaction: Default
Wrapper serialization
Generation 0: 0 collects
Generation 1: 0 collects
Generation 2: 0 collects
Time: 20.363 s
------------------------
Array serialization
Generation 0: 0 collects
Generation 1: 0 collects
Generation 2: 0 collects
Time: 30.433 s
------------------------
Wrapper deserialization
Generation 0: 109 collects
Generation 1: 47 collects
Generation 2: 16 collects
Time: 71.277 s
------------------------
Array deserialization
Generation 0: 129 collects
Generation 1: 57 collects
Generation 2: 19 collects
Time: 89.145 s


GC IsServer: True, GC latency: Interactive, GC LOH compaction: Default
Wrapper serialization
Generation 0: 0 collects
Generation 1: 0 collects
Generation 2: 0 collects
Time: 20.430 s
------------------------
Array serialization
Generation 0: 0 collects
Generation 1: 0 collects
Generation 2: 0 collects
Time: 30.364 s
------------------------
Wrapper deserialization
Generation 0: 4 collects
Generation 1: 3 collects
Generation 2: 2 collects
Time: 39.452 s
------------------------
Array deserialization
Generation 0: 3 collects
Generation 1: 3 collects
Generation 2: 3 collects
Time: 47.546 s

所以我的结论是

  • 包装方法有利于序列化和反序列化(后者具有更明显的效果)。
  • 在没有服务器GC的情况下运行时,阵列方法强加的GC收集开销更明显。另请注意,在不运行服务器GC并在多个线程上反序列化时,GC性能影响非常严重(结果未包括在内)。

希望有人觉得这很有用。

(遗憾的是,基准代码依赖于内部代码,因此我无法在此处发布完整代码。)