【问题标题】:Funq and disposing of child containerFunq 和处置子容器
【发布时间】:2013-03-19 22:50:06
【问题描述】:

我们在我们的 Windows 服务中使用 Funq 来执行一些计划任务,并且对于每一轮我们都创建一个子容器而不是创建我们所有的对象,并且在最后处理子容器时,我们发现由这个子容器创建的元素是不是 GC 作为根容器有子容器的集合,这些子容器在调用子容器的处置后保留在那里。此代码重现了我们的问题,并将消耗(并保留)800MB 内存。

对我们来说很奇怪,以这种方式使用 funq 是否只是错误的模式,在这种情况下我们应该如何使用它?还是只是一个错误?

谢谢

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");
        }
    }
}

【问题讨论】:

    标签: .net garbage-collection servicestack funq


    【解决方案1】:

    通过查看Funq sources 中的 Container.cs(最后一次更新是在 2011 年), 我可以看出它会泄漏子容器。

    CreateChildContainer 方法创建新容器,将其与父容器连接 并将创建的引用添加到 childContainers 堆栈。

    只有两个地方用到了childContainers栈:

    • childContainers.Push(child);在 Container.CreateChildContainer() 中(第 73 行)

    • childContainers.Pop().Dispose();在 Container.Dispose() 中(第 88 行)

    因此,如果您创建子容器,然后处置它(但不是它的父容器) - 对已处置子项的引用保留在父项中,因为没有清理代码 这将从父堆栈中删除已处理的引用。

    也许您可以通过创建代理子容器(仅一次)来解决此问题, 然后从中派生所有真正的子容器。由于 Dispose 方法确实 不要将对象转移到不可用状态 - 你可以清理所有孩子 一遍又一遍地为代理子调用 Dispose:

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

    【讨论】:

      【解决方案2】:

      这个问题是由于父容器有一个子容器的引用,即使子容器被释放了。垃圾收集器适用于大多数情况,但我认为这是极端情况。最简单的方法是,如果容器父级不为空,我们从父级的子级集合中删除容器引用。

      您可以从this unit test(您的代码sn-p)和its implementation查看方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多