2009-05-07 35 views
14

Có thể thiết lập kích thước tối thiểu của một đống 0 thế hệ trong .NET không?Thế hệ .NET 0 kích thước heap

Tôi có một sự phân định theo nhóm. Tôi có một hàm phân bổ khoảng 20-30 MB đối tượng 1KB, thực hiện điều gì đó với chúng và chấm dứt, để lại tất cả các đối tượng được phân bổ là GC-ed. Bây giờ, trong Performance Monitor, tôi có thể thấy rằng kích thước heap 0 thế hệ là 5-6 MB, điều đó là không đủ để chấp nhận tất cả 20-30 MB đối tượng mà tôi cần. Khi tôi bắt đầu phân bổ, tại một số điểm gen0 GC bắt đầu chạy, và vì tất cả các đối tượng là cần thiết, nó thúc đẩy chúng thành gen1. Lần tiếp theo GC bắt đầu chạy, các đối tượng này được thăng hạng trong gen2. Vì vậy, cuối cùng khoảng 15MB đối tượng của tôi kết thúc trong heap gen2. Đây là, bởi logic của tôi, các đối tượng tạm thời mà không có cách nào kết thúc trong heap gen2. Tôi tin rằng vấn đề là kích thước của kích thước heap gen0. Nhưng tôi không chắc chắn. Tôi biết rằng trong Java có một khả năng để thiết lập một kích thước tối thiểu của đống thế hệ. Có cách nào trong .NET?

Trả lời

3

Bạn có chắc chắn không còn tham chiếu đến các đối tượng này nữa không? GC là rất điều chỉnh chính nó theo nhu cầu của ứng dụng của bạn và sẽ không quảng cáo các đối tượng cho Thế hệ 2 trừ khi bạn có nguồn gốc cho những đối tượng đó ở đâu đó.

Tôi nghĩ nếu bạn tìm ra những gốc rễ này ở đâu và đảm bảo rằng bạn không còn tham khảo những đối tượng này ở đâu thì GC sẽ bắt đầu giải phóng bộ nhớ cho những đối tượng đó và không bao giờ quảng bá chúng. nếu bạn làm điều này thì GC sẽ phát hiện rằng bạn cần thế hệ 0 để lớn hơn và sẽ tăng kích thước của heap thay cho bạn.

+1

Đối tượng lớn hơn 85K nói chung không đủ điều kiện để thu thập ngoại trừ trong Gen2. Nếu một tham chiếu đến một đối tượng mới được lưu trữ trong một đối tượng lớn hơn 85K, thì trừ khi tham chiếu bên trong đối tượng lớn bị hủy, đối tượng mới sẽ tăng lên Gen2 trước khi nó trở thành đủ điều kiện để thu thập, ngay cả khi đối tượng bị hủy bỏ trước đó. – supercat

1

+1 đến Andrew. GC là tự điều chỉnh nó tìm hiểu về các mẫu bộ nhớ cần thiết của ứng dụng khi đang di chuyển.
Trong trường hợp của bạn, nếu GC thực hiện một bộ sưu tập của Gen 0 và thấy rằng rất nhiều đối tượng sống sót/không có nhiều bộ nhớ được khai hoang, bộ thu gom rác sẽ tự động tăng ngân sách Gen 0/hạn ngạch.

Nhìn vào GC Type members, dường như không có cách nào để lập cấu hình ngân sách/kích thước của GC Generation.

8

Kích thước của các thế hệ khác nhau là chi tiết triển khai và tôi không biết bất kỳ cách nào để điều chỉnh cho các ứng dụng .NET. Nếu bộ nhớ của tôi phục vụ cho tôi một cách chính xác 0 và 1 chia sẻ một phân đoạn duy nhất, là 16 MB trong Win32, vì vậy nếu bạn tạo ra rất nhiều đối tượng, một số sẽ được đẩy lên các thế hệ cao hơn nếu chúng vẫn được tham chiếu (giống như Bạn miêu tả).

Tôi đoán ý tưởng đằng sau việc giới hạn kích thước của thế hệ 0 là đảm bảo bộ sưu tập g0 rẻ. Nếu thế hệ 0 có thể phát triển đến bất kỳ kích thước nào, hiệu suất tổng thể của bạn rất có thể sẽ bị ảnh hưởng.

EDIT: Tôi tin rằng cuốn sách của Jeffrey Richter có một số chi tiết về điều này, vì vậy bạn có thể muốn kiểm tra điều đó.

EDIT2: Trạng thái phong phú hơn (tr. 502-507) mà ngân sách ban đầu của thế hệ 0 là 256 KB và ngân sách ban đầu của thế hệ 1 là 2 MB. Tuy nhiên, đó không phải là kích thước của thế hệ. Ngân sách được điều chỉnh khi cần và sẽ tăng và thu nhỏ theo mức sử dụng bộ nhớ của ứng dụng.

Joe .NET Framework 2.0 chuyên nghiệp của Joe Duffy tuy nhiên, cho biết rằng các thế hệ ephermal (tức là 0 và 1) chia sẻ một phân đoạn, đó là 16 MB (tr. 117). Chỉ thế hệ 2 mới được phép phát triển khi cần thiết (tôi cho rằng LOH được phép phát triển khi cần thiết, nhưng điều đó không rõ ràng đối với tôi từ văn bản).

+1

Gen 0 là 256KB (phù hợp với bộ nhớ cache l2 của CPU) Gen1 2MB Gen2 10MB theo sách thứ hai của Richter. Tất nhiên những điều này có thể thay đổi ... – Gishu

+0

Theo Richter, đó là ngân sách của thế hệ 0 và 1 tương ứng. Vui lòng xem chỉnh sửa của tôi để biết chi tiết. –

3

Heap thế hệ 0 ban đầu được định kích thước cho bộ nhớ cache của CPU của bạn.Điều này là để các đối tượng tạm thời nhỏ thậm chí không cần phải được chuyển đến bộ nhớ chính.

+0

Tôi hiện đang giám sát một ứng dụng có kích thước heap gen0 trên 500 mb. Vì vậy kích thước heap gen0 = kích thước bộ nhớ cache cpu. – sisve

+0

Xem thêm http://blogs.msdn.com/b/johan/archive/2007/04/20/memory-management-in-the-net-framework.aspx. Tôi có lẽ nên chỉnh sửa câu trả lời của tôi để làm cho nó chính xác hơn. –

0

Tôi không nghĩ có bất kỳ tùy chọn nào để đặt các giá trị này trong .NET GC.

Thoạt nhìn, có vẻ như tình hình cụ thể biện minh cho sự cần thiết phải có như vậy tiến tùy chọn, nhưng nếu điều này sẽ là một tĩnh tùy chọn mà nó sẽ ảnh hưởng đến tất cả cuộc đời của bạn chương trình. Một tùy chọn động, bạn có thể đặt thời gian chạy là lý tưởng. Ngoài ra, tôi không nghĩ rằng điều này sẽ ảnh hưởng đến hiệu suất của chương trình, mặc dù nếu bạn có thể tăng kích thước (0) bạn có thể giải phóng bộ nhớ (và đạt được hiệu suất một số hiệu suất).

Vì GC tự điều chỉnh, gen (0) sẽ tự động tăng kích thước và các đối tượng BIG sẽ bị thu gom rác, sớm hay muộn.

+0

Tình hình của OP là một số lượng lớn các vật thể nhỏ cần phải truy cập được cùng một lúc ... – Gishu

3

Cảm ơn các bạn đã giúp đỡ.

Whell, sự thận trọng rất thú vị. Tôi đã không bao giờ đề cập rằng tôi đang lưu trữ những 30MB của các đối tượng trong một kích thước whoose mảng là 100000. Tôi lần đầu tiên phân bổ mảng đó và sau đó điền nó với các đối tượng. Vì mảng đó lớn hơn 85K mảng đó được lưu trữ trong Vùng đối tượng lớn. Nó chỉ ra rằng để thu thập rác để thu thập các đối tượng trong đống đó, nó cần phải chạy bộ sưu tập gen2, do đó, mỗi khi không có đủ không gian trong Heap đối tượng lớn, nó chạy bộ thu gen2, đó là việc đánh bại hiệu suất. Đây là ví dụ đơn giản sẽ liên tục gọi bộ sưu tập gen2. Bạn cần phải chạy nó trong chế độ gỡ lỗi (vì tối ưu hóa trình biên dịch).

static void Main(string[] args) 
{ 
    while (true) 
    { 
     byte[] objects = new byte[100000]; 
    } 
} 

Điều này có nghĩa là bất cứ khi nào tôi cần một mảng tạm thời có kích thước lớn hơn 85K, mảng đó sẽ kết thúc trong vùng đối tượng mục tiêu?

+0

Bạn có thể đã tiếp tục kể từ câu hỏi này, chỉ là một ý nghĩ của tôi khi đọc nó. Nếu bạn có thể sử dụng cấu trúc thay vì các lớp, điều này sẽ làm giảm áp lực của GC vì nó chỉ phải phân bổ toàn bộ mảng như một khối liên tục của bộ nhớ và xóa nó thành một khối, nó sẽ chỉ có một ref cho mảng đó bản thân các mục là giá trị không phải là đối tượng. Sau đó 'stackalloc' (thay vì 'mới') có thể giúp bạn định vị và giải phóng nó nhanh hơn, mặc dù bạn thực sự cần phải làm như vậy vì nó không an toàn. – gjvdkamp

2

Tại thế hệ đầu tiên0 có thể tăng và giảm nhưng trong tương lai. khi quá trình chạy đống được quản lý khởi tạo có kích thước cố định trong thế hệ0 256 KB (có nghĩa là Richter) vì các máy tính hiện đại có bộ nhớ 256 và nhiều hơn cho tiền mặt CPU cấp 2. Thứ hai. Andrew, bạn nói đúng. Khi một số đối tượng quá lớn, nó đi đến gen2 cùng một lúc. Tôi có thể giả sử bạn muốn giảm kích thước gen0 để kích thích thường xuyên hơn được gọi là GC để xóa không gian chưa sử dụng và giữ cho ứng dụng của bạn nhẹ hơn. Tôi có cùng một vấn đề trong một trang web SilverLight và tìm kiếm một giải pháp. Tôi nghĩ rằng nếu mã tạo ra nhiều đối tượng có gốc và khi gen0 là CLR đầy đủ gọi GC mà di chuyển chúng đến gen1, và sau đó khi các đối tượng phát triển hơn di chuyển chúng đến gen2. Hãy nói rằng tất cả 3 thế hệ đã gần đầy. Sau đó, ví dụ GC gọi. Nó sẽ làm gì. Chỉ cần rõ ràng generation0? Làm thế nào với những người 1 và 2. Tôi nghĩ rằng sollution để giữ cho ánh sáng bộ nhớ là như sau. Đầu tiên tạo ra các đối tượng nhỏ và nhiều thay vì kích thước lớn và ít tính. Các đối tượng thứ hai tham chiếu nội bộ phải là một chiều hướng và không tham chiếu hỗn loạn với nhau. Các đối tượng tĩnh không được tạo động như ví dụ theo các bản ghi bắt nguồn từ cơ sở dữ liệu, cần giữ các biến toàn cầu và không tạo lại khi mã cals chúng.

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