C# 序列化大型对象图会导致protobuf网络中的无止境循环
我试图用protobuf net序列化一个大型对象图,大约250万个条目,但应用程序似乎陷入了一个无休止的循环中。内存消耗在20-40GB之间波动,它使用100%的CPU核心 序列化约200万个对象的图形效果很好,并生成850 MB的文件 我能做些什么来防止这个问题,或者在序列化之前我必须把树分成更小的部分吗 很抱歉,我的课程有点复杂,但我认为这可能是问题的一部分。我使用的是protobuf net的2.0.0.668版。 每个路由节点包含大约50个子节点C# 序列化大型对象图会导致protobuf网络中的无止境循环,c#,serialization,protobuf-net,C#,Serialization,Protobuf Net,我试图用protobuf net序列化一个大型对象图,大约250万个条目,但应用程序似乎陷入了一个无休止的循环中。内存消耗在20-40GB之间波动,它使用100%的CPU核心 序列化约200万个对象的图形效果很好,并生成850 MB的文件 我能做些什么来防止这个问题,或者在序列化之前我必须把树分成更小的部分吗 很抱歉,我的课程有点复杂,但我认为这可能是问题的一部分。我使用的是protobuf net的2.0.0.668版。 每个路由节点包含大约50个子节点 [ProtoContract()] p
[ProtoContract()]
public class Tree
{
public Tree() { }
[ProtoMember(1, DataFormat = DataFormat.Group)]
public byte[] SomeValues { get; set; }
[ProtoMember(2, DataFormat = DataFormat.Group)]
public RoutingNode Root { get; set; }
}
[ProtoContract(SkipConstructor = true), ProtoInclude(101, typeof(RoutingNode)), ProtoInclude(102, typeof(LeafNode))]
public abstract class TreeNode
{
[ProtoMember(1)]
public byte[] Hash { get; set; }
[ProtoMember(2)]
public uint Id { get; set; }
public TreeNode() { }
}
[ProtoContract(SkipConstructor = true)]
public class RoutingNode : TreeNode
{
public RoutingNode() { }
static Random r = new Random();
[ProtoMember(1, DataFormat = DataFormat.Group)]
private List<TreeNode> _subTree = new List<TreeNode>();
public RoutingNode Parent { get; set; }
public void AddNode(TreeNode node)
{
if (_subTree.Count < 50 || node is LeafNode)
{
_subTree.Add(node);
}
else
{
((RoutingNode)_subTree[r.Next(_subTree.Count - 1)]).AddNode(node);
}
}
[ProtoAfterDeserialization]
protected void OnDeserialized()
{
if (_subTree == null) _subTree = new List<TreeNode>();
foreach (TreeNode node in _subTree)
{
if (node is RoutingNode)
{
(node as RoutingNode).Parent = this;
}
}
}
}
[ProtoContract(SkipConstructor = true)]
public class LeafNode : TreeNode
{
public LeafNode() { }
[ProtoMember(1)]
public int[] SomeValues { get; set; }
}
[ProtoContract()]
公共类树
{
公共树(){}
[原成员(1,DataFormat=DataFormat.Group)]
公共字节[]SomeValues{get;set;}
[原成员(2,DataFormat=DataFormat.Group)]
公共路由节点根{get;set;}
}
[ProtoContract(SkipConstructor=true)、ProtoInclude(101,typeof(RoutingNode))、ProtoInclude(102,typeof(LeafNode))]
公共抽象类树节点
{
[原成员(1)]
公共字节[]散列{get;set;}
[原成员(2)]
公共uint Id{get;set;}
公共树节点(){}
}
[协议(SkipConstructor=true)]
公共类路由节点:树节点
{
公共路由节点(){}
静态随机r=新随机();
[原成员(1,DataFormat=DataFormat.Group)]
私有列表_子树=新列表();
公共路由节点父节点{get;set;}
公共void AddNode(TreeNode节点)
{
如果(_subTree.Count<50 | |节点为LeafNode)
{
_添加(节点);
}
其他的
{
((RoutingNode)_子树[r.Next(_subTree.Count-1)]).AddNode(node);
}
}
[反序列化]
已序列化的受保护的void()
{
如果(_subTree==null)_subTree=new List();
foreach(子树中的树节点)
{
if(节点为路由节点)
{
(节点作为RoutingNode)。父节点=此;
}
}
}
}
[协议(SkipConstructor=true)]
公共类LeafNode:TreeNode
{
公共叶节点(){}
[原成员(1)]
public int[]SomeValues{get;set;}
}
示例程序
var-tree=新树();
tree.Root=新路由节点();
var r=新的随机变量();
对于(uint i=0;i<5000000;i++)
{
字节[]散列=新字节[200];
r、 下一字节(散列);
tree.Root.AddNode(新路由节点(){Hash=Hash,Id=i});
}
对于(uint j=0;j<5000;j++)
{
字节[]散列=新字节[200];
r、 下一字节(散列);
var node=newroutingnode(){Hash=Hash,Id=j};
对于(uint i=0;i<50;i++)
{
哈希=新字节[200];
r、 下一字节(散列);
AddNode(新的LeafNode(){Hash=Hash,Id=i});
}
tree.Root.AddNode(节点);
}
使用(var stream=File.OpenWrite(“test.tmp”))
ProtoBuf.Serializer.Serialize(流、树);
这棵树是纯树吗?或者它是循环的?你有什么可以复制的吗?我看到Parent
没有序列化,但是TreeNode
是否可能直接或间接地包含自身?(注意:它应该自动检测到)节点从不包含自身,树中的所有节点都应该是唯一的。我可能可以创建一个小的测试程序来重现问题。我在原始问题中添加了一个小的示例程序。我用16GB的ram在我的机器上运行它,但是内存利用率从来没有超过80%,当序列化时,应用程序在4.5-8GB之间波动。在序列化开始之前,该应用程序需要大约1.9GB的ram;我没有立即的答复,但我会的investigate@marc-您曾经解决过这个问题中的问题吗?我遇到了非常相似的问题:大对象图,内存填充和波动,无休止的循环,没有例外
var tree = new Tree();
tree.Root = new RoutingNode();
var r = new Random();
for (uint i = 0; i < 5000000; i++)
{
byte[] hash = new byte[200];
r.NextBytes(hash);
tree.Root.AddNode(new RoutingNode() { Hash = hash, Id = i });
}
for (uint j = 0; j < 5000; j++)
{
byte[] hash = new byte[200];
r.NextBytes(hash);
var node = new RoutingNode() { Hash = hash, Id = j };
for (uint i = 0; i < 50; i++)
{
hash = new byte[200];
r.NextBytes(hash);
node.AddNode(new LeafNode() { Hash = hash, Id = i });
}
tree.Root.AddNode(node);
}
using (var stream = File.OpenWrite("test.tmp"))
ProtoBuf.Serializer.Serialize(stream, tree);