오늘 웹 서버에서 메모리가 매우 빠르게 사라지는 생산 환경에서 우리는 큰 파급을 경험했습니다. 이것은 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가 계속해서 CookieContainer의 새로운 인스턴스를 가져 와서 캐싱을 수행할까요? 나는 잘못된 객체와 관련된 다른 문제가있을 것이라고 생각하지만 적어도 메모리 누수가 아닌 버그 일뿐입니다.
제 질문은 a)이 오류를 올바르게 진단 했습니까? b)이 문제가 다시 발생하지 않도록하기 위해 권장되는 접근법이 있습니까? c)이 유형의 순환 의존성을 검사하기 위해 코드에 수정을 적용 할 수 있습니까?
오늘 내 엉덩이를 구한 사람들. 우리에게는 똑같은 문제가있었습니다! – pkolodziej