4

we are using Funq in our windows service to execute some scheduled tasks, and for each round we are creating a child container than create all our objects and on the end disposing child container, we discovered that elements created by this child containers are not GC as root container has collection of child containers which stay there after calling dispose of child container. this code reproduces our issue and will consume (and keep) 800MB of memory.

for us it was quite surprising, is this just wrong pattern to use funq this way, in this case how should we use it? or is it just a bug?

thanks

public class Dummy
{
    public string Content { get; set; }
    public void Generate(int size)
    {
        this.Content = new string('X', size);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var container = new Container();
        container.RegisterAutoWired<Dummy>().ReusedWithin(ReuseScope.Container);
        int size = 20000;
        for (int i = 0; i < size; i++)
        {
            using (var c = container.CreateChildContainer())
            {
                var d= c.Resolve<Dummy>();
                d.Generate(size);
            }
            PrintInfo(i);
        }

        Console.ReadLine();
    }

    private static void PrintInfo(int i)
    {
        if (i%1000 == 0)
        {
            int divide = 1024*1024;
            GC.Collect();
            var p = System.Diagnostics.Process.GetCurrentProcess();
            Console.WriteLine(p.WorkingSet64/divide + "MB");
            Console.WriteLine(p.PrivateMemorySize64/divide + "MB");
        }
    }
}
zebra
  • 1,330
  • 1
  • 13
  • 26

2 Answers2

3

From looking at Container.cs in Funq sources (which were last updated in 2011), I can tell that it leaks child containers.

CreateChildContainer method creates new container, connects it with parent container and adds created reference to childContainers stack.

There are only two places where childContainers stack is used:

  • childContainers.Push(child); in Container.CreateChildContainer() (line 73)

  • childContainers.Pop().Dispose(); in Container.Dispose() (line 88)

So if you create child container, and then dispose it (but not its parent) - the reference to disposed child stays in parent, as there is no cleanup code which will remove disposed reference from parent's stack.

Probably you can work around this by creating proxy child container (only once), and then deriving all real child containers from it. Since Dispose method does not transfer object into unusable state - you can clean up all children by calling Dispose for proxy child, over and over again:

    var container = new Container();
    container.RegisterAutoWired<Dummy>().ReusedWithin(ReuseScope.Container);
    int size = 20000;
    var proxy = container.CreateChildContainer()
    for (int i = 0; i < size; i++)
    {
        using (proxy)
        using (var c = proxy.CreateChildContainer())
        {
            var d= c.Resolve<Dummy>();
            d.Generate(size);
        }
        PrintInfo(i);
    }
Alexander
  • 4,153
  • 1
  • 24
  • 37
0

This problem is due to the fact that the parent container has a reference of a child container even if the child container were disposed. Garbage collector works well for most scenarios but I think that this is the corner case. The easiest way would be that we remove a container reference from parent's children collection if the container parent is not null.

You can check out the way from this unit test(your code snippet) and its implementation.

Jin-Wook Chung
  • 4,196
  • 1
  • 26
  • 45