【问题标题】:Memory leaks in C# when using deep copy使用深拷贝时 C# 中的内存泄漏
【发布时间】:2014-03-27 10:47:38
【问题描述】:

我正在制作一个进化算法,但我遇到了一些内存泄漏问题。基本上我有一个由树木组成的人口。当我在两棵树之间执行交叉操作时,我想在两棵树之间交换两个子树。问题是这个过程会泄漏大量内存,导致我的程序在 30-40 代后无用。最重要的代码如下:

节点的类:

[System.Serializable]
public class TreeNode
{
    ArrayList mChildren = new ArrayList();
    TreeNode mParent;

public static TreeNode DeepClone<TreeNode>(TreeNode obj)
{
    using (var ms = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(ms, obj);
        ms.Position = 0;

        return (TreeNode) formatter.Deserialize(ms);
    }
}

public TreeNode (TreeNode parent)
{
    mParent = parent;
}
}

树的类:

[System.Serializable]
public class Tree
{
    TreeNode mRoot = new TreeNode(null);

    public static Tree DeepClone<Tree>(Tree obj)
    {
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;

            return (Tree) formatter.Deserialize(ms);
        }
    }
}

我一直在查看How do you do a deep copy of an object in .NET (C# specifically)? 进行深度复制,但我不确定它是否正确实施。

至于我的测试程序:

for (int i = 0; i < 50; i++)
{
    trees[i] = new Tree();
    trees[i].generateTree(30);
}

for (int i = 0; i < 100; i++)
{
    for (int j = 0; j < 49; j++)
    {
        trees[j].getRandomSubtree(Tree.DeepClone<Tree>(trees[j+1]));
    }
    System.GC.Collect();
}

getRandomSubtree() 函数基本上从一棵树中选择一棵随机子树,并将其与从另一棵树中随机选择的子树交换。我还确保更新子树的父引用。当我运行此代码时,我的程序泄漏了大量内存。如果我停止进行深度复制,程序就会停止泄漏内存,所以我很不明白正在发生一些事情。

【问题讨论】:

  • 如果要交换它们,为什么要进行深拷贝?只需交换参考资料。
  • 对不起,我忘了提。在我进行锦标赛选择后,我想保留父母双方并为他们创建两个孩子。通过复制父节点然后交换子树来创建子节点。

标签: c# memory-leaks evolutionary-algorithm


【解决方案1】:

我认为您不想序列化父字段。将其标记为NonSerialized。当然,你需要在反序列化后修复这个问题。

或者只是在序列化之前将其设置为null

public static TreeNode DeepClone<TreeNode>(TreeNode obj)
{
    TreeNode oldParent = obj.mParent;
    obj.mParent = null;
    using (var ms = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(ms, obj);
        obj.mParent = oldParent;

        ms.Position = 0;

        TreeNode result = (TreeNode) formatter.Deserialize(ms);
        result.mParent = oldParent;
        return result;
    }
}

【讨论】:

  • 反序列化后如何修复?我对 C# 还很陌生,对序列化概念不太满意
  • 我实现了这个,但现在 mParent 字段对于克隆子树的每个根都为空
  • 你错过了obj.mParent = oldParent;result.mParent = oldParent; 的行吗?此外,对于此代码,您不应将 mParent 标记为 NonSerialized。抱歉,如果不清楚。
  • 得到了所有的代码,在 TreeNode 我有 [System.NonSerialized] TreeNode mParent;并清除克隆中的所有 mParent 字段为空,而不仅仅是根
  • 我确实必须更改行: public static TreeNode DeepClone(TreeNode obj) 到 public static TreeNode DeepClone(TreeNode obj) 否则我在尝试添加您建议的更改时出错.不过不要认为这会影响任何事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-12
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多