Сегодня у нас произошел серьезный сбой в работе, когда память очень быстро исчезала из наших веб-серверов. Это было прослежено до механизма кэширования в 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, а CookieContainer также ссылался на HttpContext.Current. Таким образом, Ninject никогда не сможет удалить экземпляры CookieContainer из своего кэша, как экземпляры CookieContainer, в которых поддерживаются их объекты обратного вызова области действия. Когда мы изменяем область действия CookieContainer на переходную, все работает нормально, как мы и ожидали. Но я до сих пор не совсем уверен, почему это произошло, так как кажется, что это довольно обычная вещь, чтобы делать правильно? Может быть, не возможно ...
Я также сбит с толку, поскольку думал, что если объект обратного вызова остался живым, как это было, то не следует Ninject просто возвращать тот же экземпляр из кэша, видя, что обратный вызов все еще жив, поэтому экземпляр должен появиться быть в сфере? Почему бы ninject продолжать получать новые экземпляры CookieContainer и кэшировать их? Я предполагаю, что были бы другие проблемы, связанные с возвращением неправильного объекта, но это, по крайней мере, просто ошибка, а не утечка памяти.
Мой вопрос: а) правильно ли мы диагностировали эту ошибку? б) есть ли рекомендуемый подход, чтобы это не повторилось? c) Могу ли я внести исправление в код для проверки этого типа циклической зависимости (при условии, что мы правильно поставили диагноз)?