Утечка памяти ninject из-за ссылки обратного вызова круговой области

Сегодня у нас произошел серьезный сбой в производстве, когда память очень быстро исчезала с наших веб-серверов. Это было связано с механизмом кеширования в Ninject (я думаю, что это был Activation Cache или что-то в этом роде - не совсем уверен). После исследования проблемы мы пришли к выводу, что у нас есть циклическая ссылка в нашем обратном вызове области.

class View
{
    Presenter presenter;

    View()
    {
        //service locators are smelly, but webforms forces this uglyness
        this.presenter = ServiceLocator.Get<Func<View, Presenter>>()(this);

        this.presenter.InitUI();
    }
}

class Presenter
{
    CookieContainer cookieContainer;
    View view;

    Presenter(View view, CookieContainer cookieContainer)
    {
        this.view = view;
        this.cookieContainer = cookieContainer;
    }
}

class CookieContainer
{
    HttpRequest request;
    HttpResponse response; 

    CookieContainer()
    {
        this.request = HttpRequest.Current.Request;
        this.response = HttpRequest.Current.Response;
    }
}

Bind<Func<View, Presenter>>().ToMethod(ctx => view => 
        ctx.Kernel.Get<Presenter>(new ConstructorArgument("view", view)));

Bind<Presenter>().ToSelf().InTransientScope();
Bind<CookieContainer>().ToSelf().InRequestScope();

Это представление нашего кода, который вызывал Похоже, что произошло то, что произошло: обратным вызовом области для CookieContainer был HttpContext.Current, а на HttpContext.Current также ссылался CookieContainer. Таким образом, Ninject никогда не мог удалить экземпляры CookieContainer из своего кеша, поскольку экземпляры CookieContainer сохраняли свои объекты обратного вызова области жив. Когда мы меняем область действия CookieContainer на временную, все работает нормально, как мы и ожидали. Но я до сих пор не совсем уверен, почему это произошло, поскольку кажется, что это довольно совместная обычное дело делать правильно? Может быть, не возможно ...

Я также запутался, так как думал, что если объект обратного вызова остался живым, как и был, то Ninject не должен просто вернуть тот же экземпляр из кеша, поскольку обратный вызов все еще был жив, поэтому экземпляр должен появиться попасть в сферу охвата? Почему ninject будет продолжать получать новые экземпляры CookieContainer и кэшировать их? Я предполагаю, что возникнут и другие проблемы, связанные с возвращением некорректного объекта, но это, по крайней мере, будет просто ошибкой, а не утечкой памяти.

У меня вопрос: а) правильно ли мы диагностировали эту ошибку? б) есть ли рекомендуемый подход, чтобы это не повторилось? c) Могу ли я внести исправление в код, чтобы проверить этот тип циклической зависимости (при условии, что мы правильно диагностировали это)?

7
задан AaronHS 16 February 2012 в 09:56
поделиться