2012-01-06 26 views
6

Tôi có một ứng dụng web ASP.NET/C# đang sử dụng rất nhiều bộ nhớ.Gen lớn 0 Heap trong .NET, lãng phí bộ nhớ?

ANTS Memory Profiler và PerfMon cho thấy cả đống Gen 0 của tôi phát triển nhanh chóng với kích thước khoảng 1 GB trong suốt quá trình Application_Start. Tôi đọc here rằng bộ đếm PerfMon cho Gen 0 Heap thực sự hiển thị "ngân sách" cho Gen 0, không phải kích thước (nghĩa là không phải tất cả bộ nhớ đó là một phần của bộ làm việc riêng của quy trình?). Tuy nhiên, trình lược tả ANTS hiển thị khoảng 700 MB "bộ nhớ không sử dụng được cấp phát cho .NET", và này dường như là một phần của quá trình làm việc riêng tư (như được báo cáo trong taskmgr). Tôi đoán số lượng lớn bộ nhớ không sử dụng này có liên quan đến đống Gen 0 lớn.

Điều gì đang xảy ra trong Application_Start trong khi điều này xảy ra là tôi đang trong một vòng lặp while đọc khoảng một triệu hàng từ một SqlDataReader. Chúng đang được sử dụng để cư trú một bộ nhớ cache lớn để sử dụng sau này. Với điều này, thủ phạm rõ ràng đối với số lượng lớn bộ nhớ không sử dụng là phân mảnh đống đối tượng lớn, nhưng tôi không nghĩ đây là trường hợp vì tôi đang phân bổ trước nhiều hơn là cần thiết cho đối tượng bộ nhớ cache lớn của tôi. Để chắc chắn, tôi thậm chí đã cố gắng bình luận ra một phần của vòng lặp mà thực sự thêm vào đối tượng bộ nhớ cache của tôi; nó không có sự khác biệt về lượng bộ nhớ không sử dụng được cấp phát. Là một thử nghiệm, tôi đã cố gắng thường xuyên buộc thu gom rác của gen 0 trong vòng lặp (chống lại tất cả các khuyến nghị, tôi biết), và điều này khiến kích thước của heap gen0 giảm xuống còn khoảng 128 MB và cũng chỉ dẫn đến một vài MB bộ nhớ trống không sử dụng. Nhưng nó cũng maxed ra CPU của tôi và làm cho Application_Start mất quá nhiều thời gian.

Câu hỏi của tôi là:

1) Điều gì có thể gây ra kích thước báo cáo của Gen 0 Heap phát triển quá lớn?

2) Đây có phải là sự cố không? Đặc biệt, nó có thể gây ra một lượng lớn không gian không sử dụng được cấp cho .NET không?

3) Nếu có, tôi nên làm gì để khắc phục sự cố? Nếu tôi không thể ngăn chặn quá trình sử dụng nhiều bộ nhớ đó trong Application_Start, tôi muốn ít nhất có thể làm cho nó mất bộ nhớ khi ứng dụng bắt đầu hoàn thành.

+0

Điều gì sẽ xảy ra nếu bạn làm một thùng rác đầy đủ * đơn * được thu thập ở cuối Application_Start? –

+0

Một bộ sưu tập rác đầy đủ ở cuối Application_Start đã không tạo ra sự khác biệt. Vấn đề là ngay cả sau khi số lượng lớn các vật thể sống ngắn được thu thập, tất cả ký ức mà họ * đã * đang chiếm vẫn được cấp phát cho quá trình này. –

+0

Tuy nhiên, tôi không còn tin rằng đây là một vấn đề. Hoặc bộ nhớ cuối cùng được phát hành bởi quá trình, hoặc nếu tổng bộ nhớ bắt đầu lấp đầy trước khi điều đó xảy ra, sau đó nó có thể được hoán đổi vào đĩa. Câu hỏi này giải quyết một mối quan tâm tương tự: http: // stackoverflow.com/questions/5244980/khi-là-bộ nhớ-phân bổ-by-net-quá trình phát hành-back-to-windows –

Trả lời

4

Gen 0 chứa "đối tượng trẻ nhất, được phân bổ gần đây nhất" và tách biệt với LOH. Những gì nó âm thanh như là bạn đang phân bổ tấn và tấn của các đối tượng nhỏ (tất cả các errata kết hợp với các mục cache, bởi âm thanh của nó) mà không được giải phóng (thể hiện bởi GC thường xuyên giữ kích thước xuống) nhưng không làm sạch một cách kịp thời bởi vì GC chưa cho là cần thiết. GC chỉ đơn giản là chưa thấy một nhu cầu để làm sạch. Máy có bao nhiêu RAM? Tôi đoán rằng bạn không phân trang.

Sự hiểu biết của tôi là .NET có thể trả về các khối không sử dụng cho hệ điều hành khi GC cho rằng nó không còn cần thiết nữa (ví dụ: khoảng trống đó đã không được sử dụng trong một thời gian dài). Bạn đã quan sát ứng dụng trong một thời gian dài, để xem liệu điều này có xảy ra không? Nếu bạn không phân trang, tôi không nghĩ rằng đó là một vấn đề.

+0

Cảm ơn, Chris. Tôi đã nghĩ rằng một cái gì đó như thế này có thể là trường hợp (các nhà sưu tập rác chờ một thời gian để làm sạch các đối tượng nhỏ từ lần lặp trước của vòng lặp), nhưng những gì tôi muốn đọc là khi Gen 0 được lấp đầy mà gây nên một bộ sưu tập. Rõ ràng GC có thể chọn tăng kích thước của Gen 0 thay vì thu thập nó; điều đó có đúng không? –

+0

Đó là sự thật. Đó là một bài tập suy nghĩ đơn giản - sẽ không thể vào lúc khởi động để CLR phân bổ trước kích thước heap thích hợp cho ứng dụng của bạn, vì vậy khả năng duy nhất là nó bắt đầu rất nhỏ (cho "Hello world") và phân bổ thêm không gian cần thiết. –

+0

Hộp kiểm tra Tôi đang chạy profiler trên có rất nhiều bộ nhớ miễn phí; những gì thực sự nhắc nhở điều tra là các ứng dụng của chúng tôi trên các máy chủ trực tiếp đang đạt ngưỡng bộ nhớ và tái chế thường xuyên hơn chúng tôi muốn. (Phần lớn sự tiêu thụ bộ nhớ này xảy ra sau đó, nhưng cố gắng giảm sử dụng bộ nhớ dường như quá mức trong khi bắt đầu ứng dụng dường như là một nơi tốt để bắt đầu.) Nhưng thỉnh thoảng chúng ta quan sát thấy những giọt lớn trong việc sử dụng bộ nhớ; có lẽ đó là GC trả lại một đoạn không sử dụng đống như bạn nói. Tôi cho rằng tôi chỉ phải chờ GC quyết định làm điều này; Tôi không thể nhắc nó? –

Các vấn đề liên quan