今天我們在生產中發生了重大中斷,其中內存從我們的Web服務器快速消失。這可以追溯到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只是從緩存回傳相同的實例,看起來好像回調仍然是活着,所以實例應該在範圍內?爲什麼會不停地獲取CookieContainer的新實例並緩存它們?我想還會有其他問題與不正確的對象有關,但這至少只是一個錯誤,而不是內存泄漏。
我的問題是a)我們是否正確診斷出這個錯誤? b)有沒有建議採取這種做法不要再發生? c)我可以修復代碼來檢查這種類型的循環依賴(假設我們已經正確診斷)嗎?
你今天救了我屁股的人。我們有完全相同的問題! – pkolodziej 2014-01-03 21:48:27