Ninject缓存对象,应该处理,memoryleak?

时间:2013-05-27 14:31:12

标签: c# ninject

内存泄漏时,没有对象在ninject内部的weakreferencecollection中处理,我做错了什么或者ninject中有一个巨大的错误?

当Kernal被释放时,所有引用都会从弱引用集合中被释放,但是在此循环中,即使没有代码引用 - 内存也会爆炸。

public class Program
{
    private StandardKernel kernel;

    private static void Main(string[] args)
    {
        new Program().Run();
    }

    public void Run()
    {
        kernel = new StandardKernel(new NinjectSettings() { LoadExtensions = false });
        kernel.Bind<Root>().ToSelf();
        kernel.Bind<Foo>().ToSelf().InCallScope();

        while (true)
        {
            Process();

            Thread.Sleep(500);

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }

    public void Process()
    {
        Root root = kernel.Get<Root>();
        Root root2 = kernel.Get<Root>();
    }

    public class Root
    {
        private Foo _test;

        public Root(Foo foofac)
        {
            Id = Guid.NewGuid();
            _test = foofac;
        }

        protected Guid Id { get; set; }
    }

    public class Foo
    {
    }
}

更新

我尝试过使用命名范围,甚至在例子中使用工厂: http://www.planetgeek.ch/2012/04/23/future-of-activation-blocks/ 但仍然在memoryprofiler中,弱引用集合随着时间的推移而爆炸,这不太好......我目前的测试代码是:

public class Program
{
    private StandardKernel kernel;

    private static void Main(string[] args)
    {
        new Program().Run();
    }

    public void Run()
    {
        kernel = new StandardKernel(new NinjectSettings() { LoadExtensions = false });
        kernel.Load<FuncModule>();

        kernel.Bind<IRootFactory>().ToFactory();
        var scopeParameterName = "scopeRoot";
        kernel.Bind<Root>().ToSelf().DefinesNamedScope(scopeParameterName);
        kernel.Bind<Foo>().ToSelf().InNamedScope(scopeParameterName);


        while (true)
        {
            Process();

            GC.Collect();
            GC.WaitForPendingFinalizers();

            Thread.Sleep(500);
        }
    }

    public void Process()
    {
        Root root = kernel.Get<IRootFactory>().CreateRoot();
        Root root2 = kernel.Get<IRootFactory>().CreateRoot();
    }

    public class Root
    {
        private Foo _test;

        public Root(Foo foofac)
        {
            Id = Guid.NewGuid();
            _test = foofac;
        }

        protected Guid Id { get; set; }
    }

    public class Foo
    {
    }

    public  interface IRootFactory
    {
        Root CreateRoot();
    }
}

2 个答案:

答案 0 :(得分:1)

这需要时间,而不是确定性的 - 请参阅真实的impl代码和精神的the Cache and Collect article

在你的例子中,你应该等待Ninject Releasing机制被触发(关闭计时器IIRC)。 def不做的一件事是同步Dispose并释放第二个GC发生。

最重要的是,您最好通过IResolutionRoot.Releasenamed scopes allied to InRequestScope确定性地执行发布。

答案 1 :(得分:1)

不是我建议使用它,但GC.Collect()是一种异步机制。调用它只会触发GC发生,它不会等待它完成。如果你担心它,你可能想要致电GC.WaitForPendingFinalizers()