C# 序列化大型对象图会导致protobuf网络中的无止境循环

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

我试图用protobuf net序列化一个大型对象图,大约250万个条目,但应用程序似乎陷入了一个无休止的循环中。内存消耗在20-40GB之间波动,它使用100%的CPU核心

序列化约200万个对象的图形效果很好,并生成850 MB的文件

我能做些什么来防止这个问题,或者在序列化之前我必须把树分成更小的部分吗

很抱歉,我的课程有点复杂,但我认为这可能是问题的一部分。我使用的是protobuf net的2.0.0.668版。 每个路由节点包含大约50个子节点

[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);