6

Chúng tôi đã có một sự cố ngừng hoạt động lớn trong ngày hôm nay trong sản xuất, nơi bộ nhớ đã biến mất rất nhanh chóng từ máy chủ web của chúng tôi. Điều này đã được truy trở lại một cơ chế bộ nhớ đệm trong Ninject (tôi nghĩ rằng đó là Activation Cache hoặc một cái gì đó - không hoàn toàn chắc chắn). Sau khi điều tra vấn đề chúng tôi đi đến kết luận rằng chúng tôi đã có một tham chiếu vòng tròn trong phạm vi gọi lại của chúng tôi.rò rỉ bộ nhớ ninject do tham chiếu callback phạm vi tròn

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(); 

Đây là đại diện cho mã của chúng tôi đã gây ra sự cố. Dường như những gì đã xảy ra là phạm vi gọi lại cho CookieContainer là HttpContext.Current, và HttpContext.Current cũng đang được tham chiếu bởi CookieContainer. Vì vậy Ninject không bao giờ có thể cắt xén các cá thể CookieContainer từ bộ nhớ cache của nó, như các cá thể CookieContainer, nơi giữ các đối tượng gọi lại phạm vi của chúng còn sống. Khi chúng ta thay đổi phạm vi của CookieContainer thành thoáng qua, tất cả đều hoạt động tốt, như chúng ta mong đợi. Nhưng tôi vẫn không hoàn toàn chắc chắn tại sao điều này xảy ra vì nó có vẻ như đây là một điều khá thông thường để làm đúng? Có lẽ không phải là ...

Tôi cũng bối rối vì tôi nghĩ rằng nếu đối tượng gọi lại vẫn còn sống như nó đã làm, thì không nên Ninject chỉ cần quay trở lại cùng một thể hiện từ bộ nhớ cache, nhìn như thể gọi lại vẫn còn còn sống, do đó, các trường hợp nên xuất hiện để được trong phạm vi? Tại sao ninject tiếp tục nhận được các phiên bản mới của CookieContainer và lưu chúng vào bộ đệm? Tôi đoán sẽ có những vấn đề khác liên quan đến đối tượng không chính xác quay trở lại, nhưng điều đó sẽ ít nhất chỉ là một lỗi, không phải là một rò rỉ bộ nhớ.

Câu hỏi của tôi là a) chúng tôi đã chẩn đoán lỗi này chính xác chưa? b) có cách tiếp cận được khuyến nghị để thực hiện điều này không xảy ra lần nữa không? c) Tôi có thể đặt một sửa chữa vào mã để kiểm tra loại phụ thuộc vòng tròn này (giả sử chúng tôi đã chẩn đoán chính xác điều này)?

Trả lời

7

Đơn giản chỉ cần mô tả, bộ nhớ cache là từ điển của đối tượng phạm vi tham chiếu yếu đối với cá thể. Miễn là phạm vi còn sống, các đối tượng được tham chiếu cũng được giữ nguyên. Vì vậy, có nếu CookieContainer của bạn referneces HttpContext.Current và là trong phạm vi yêu cầu cơ chế tiêu chuẩn này sẽ không bao giờ áp dụng để phát hành chúng.

Nhưng trong trường hợp đặc biệt của InRequestScope có một cơ chế giải phóng khác được thực hiện bởi OnePerRequestModule sẽ giải phóng tất cả đối tượng InRequestScoped ngay sau khi yêu cầu hoàn tất. Nếu bạn đang sử dụng một phiên bản cập nhật của Ninject.Web hoặc Ninject.Web.MVC3 thì nó được cấu hình sẵn. Nếu không, bạn phải thêm nó một cách rõ ràng bằng cách cấu hình HTTPModule này trong web.config.

Điểm khác mà bạn không hiểu là Ninject sẽ không trả về cùng một đối tượng miễn là nó tồn tại. Ví dụ. trong phạm vi yêu cầu, nó sẽ trả về cùng một đối tượng cho một yêu cầu. Nếu nhiều yêu cầu chạy cùng một lúc thì tất cả chúng đều có một phiên bản khác.

+0

Các bạn đã lưu ass của tôi hôm nay. Chúng tôi đã có chính xác cùng một vấn đề! – pkolodziej