Heyup。 protobuf.net的长期爱好者。
快速提问。我有一个高度多线程的C#应用程序,可以反序列化大约100个对象/秒,大约50MB /秒。我看到非常大的内存使用量,远远超过我正在反序列化的内存。我通过'Red Gate ANTS Memory Profiler'运行应用程序,由于protobuf(超过50%的应用程序使用),它向我展示了大量的第2代内存对象。大多数对象都是int值,并与以下内容链接:
- TypeModel.TryDeserializeList()
- ProtoBuf.Meta.BasicList
任何有助于减少第二代内存使用的帮助都将受到赞赏。
马克
答案 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的回答我做了一个快速的
基准测试基准测试创建了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
所以我的结论是
希望有人觉得这很有用。
(遗憾的是,基准代码依赖于内部代码,因此我无法在此处发布完整代码。)