Как освободить память из IEnumerable - PullRequest
0 голосов
/ 28 июня 2018

Я делаю программу, которая распечатывает все узлы в дереве Коллатца в C #. Это занимает много памяти, и outOfMemoryExceptions стали словом дня. База программы выглядит следующим образом:

        var fileStream = File.Create("collatz.txt"); //just print into a textfile for testing
        var writer = new StreamWriter(fileStream);

        IEnumerable<Node> nodeList = new List<Node>()
        {
            new Node(1, null) //rootNode
        };
        Task flushTask = Task.CompletedTask;
        while (nodeList.Any())
        {
            var tempList = CalcChildren(nodeList); //Return a IEnumerable of children of all the parents in the nodeList
            await flushTask;
            foreach (var node in tempList)
                writer.WriteLine($"{node.Value} -> {node.Parent.Value}: {node.StepsFromRoot}");
            flushTask = writer.FlushAsync();
            nodeList = tempList;
        }

        writer.Close();

    static IEnumerable<Node> CalcChildren(IEnumerable<Node> parents)
    {
        foreach(var parent in parents)
            foreach (var child in CalcChildren(parent))
                yield return child;
    }

    static IEnumerable<Node> CalcChildren(Node parent)
    {
        var multiValue = parent.CalcMultiplicationValue();
        if (multiValue.HasValue)
        {
            var child = new Node(multiValue.Value, parent);
            parent.MultiplicationChild = child;
            yield return child;
        }
        var divValue = parent.CalcDivisionValue();
        if (divValue.HasValue && divValue.Value!=1)
        {
            var child = new Node(divValue.Value, parent);
            parent.DivisionChild = child;
            yield return child;
        }
    }

Я думаю, что здесь кроется проблема, но ради полноты, класс Node:

    public class Node
{
    public Node(int value, Node parent)
    {
        Value = value;
        Parent = parent;
        if (parent != null)
            StepsFromRoot = parent.StepsFromRoot+1;
        else
            StepsFromRoot = 0;
    }

    public int Value { get; }
    public Node Parent { get; set; }

    public Node DivisionChild { get; set; }

    public Node MultiplicationChild { get; set; }

    public int StepsFromRoot { get; set;  }

    public int? CalcMultiplicationValue()
    {
        if(Value<=int.MaxValue/2)
            return 2 * Value;
        return null;
    }

    public int? CalcDivisionValue()
    {
        double newValue = (Value - 1) / 3.0;
        if (newValue % 2 == 1 && newValue >= 1)
            return (int)newValue;
        return null;
    }
}

Я стараюсь изо всех сил отбросить как можно больше памяти, но, похоже, это не работает. На 105-й итерации эта программа занимает 4 ГБ памяти! Сначала я подумал, что это потому, что буфер моего писателя занимал всю память. Теперь я думаю, что это потому, что сборка узлов не очищается сборщиком мусора.

Я пытался сделать его более минимальным. Но я не уверен, что удалить, сохраняя его полным. Заранее спасибо!

...