2009-07-19 30 views
12

Tôi đã đọc về vấn đề này trên MSDN và trên CLR qua C#.Điểm của việc sử dụng GC.AddMemoryPressure với tài nguyên không được quản lý là gì?

Hãy tưởng tượng chúng tôi có một bản phân phối HBITMAP không được quản lý 2Mb và bitmap được quản lý 8 byte trỏ đến nó. Điểm của việc nói cho GC về nó với AddMemoryPressure là gì nếu nó không bao giờ có thể làm bất cứ điều gì về đối tượng, vì nó được phân bổ như tài nguyên không được quản lý, do đó, không dễ bị thu gom rác?

Trả lời

9

Điểm AddMemoryPressure là cho bộ thu gom rác biết rằng có một lượng lớn bộ nhớ được phân bổ với đối tượng đó. Nếu nó không được quản lý, người thu gom rác không biết về nó; chỉ phần được quản lý. Vì phần được quản lý là tương đối nhỏ, GC có thể cho phép nó vượt qua để thu gom rác nhiều lần, về cơ bản lãng phí bộ nhớ có thể cần phải được giải phóng.

Có, bạn vẫn phải phân bổ và phân bổ thủ công bộ nhớ không được quản lý. Bạn không thể thoát khỏi điều đó. Bạn chỉ cần sử dụng AddMemoryPressure để đảm bảo rằng GC biết nó ở đó.

Edit:

Vâng, trong trường hợp một, tôi có thể làm điều đó, nhưng nó muốn làm cho không có sự khác biệt lớn, như GC sẽ không thể làm một điều về kiểu của tôi , nếu tôi hiểu điều này một cách chính xác: 1) Tôi muốn khai báo biến của tôi, 8 byte được quản lý, 2MB byte không được quản lý. Sau đó tôi sẽ sử dụng nó, gọi vứt bỏ, vì vậy bộ nhớ không được quản lý được giải phóng. Ngay bây giờ nó sẽ chỉ ocuppy 8 byte. Bây giờ, với đôi mắt của tôi, đã được gọi trong AddMemoryPressure và RemoveMemoryPressure bắt đầu ở cuối sẽ không có gì khác biệt. Tôi đang làm gì sai? Xin lỗi vì đã anoying về điều này. - Jorge Branco

Tôi nghĩ rằng tôi gặp sự cố của bạn.

Có, nếu bạn có thể đảm bảo rằng bạn luôn gọi Dispose, thì có, bạn không cần phải bận tâm với AddMemoryPressure và RemoveMemoryPressure. Không có sự tương đương, vì tham chiếu vẫn tồn tại và loại sẽ không bao giờ được thu thập.

Điều đó nói rằng, bạn vẫn muốn sử dụng AddMemoryPressure và RemoveMemoryPressure, vì mục đích đầy đủ. Điều gì sẽ xảy ra nếu, ví dụ, người dùng lớp học của bạn quên gọi Dispose?Trong trường hợp đó, giả sử bạn đã triển khai mẫu Xử lý đúng cách, bạn sẽ kết thúc việc xác nhận lại các byte không được quản lý của mình khi hoàn tất, tức là khi đối tượng được quản lý được thu thập. Trong trường hợp đó, bạn muốn áp lực bộ nhớ vẫn hoạt động, để đối tượng có nhiều khả năng được khai hoang hơn.

+0

Vâng, điều đó không trả lời câu hỏi, lol. –

+0

Tôi đã nói gần như chính xác những gì Steven Lyons nói, chỉ theo một cách khác. Làm sao nó không trả lời được câu hỏi? – Randolpho

+0

Vâng, thực sự tôi đã đọc lại và chỉnh sửa bài đăng của mình. –

13

Nó được cung cấp để GC biết chi phí thực sự của đối tượng trong khi thu thập. Nếu đối tượng thực sự lớn hơn kích thước được quản lý phản ánh, nó có thể là một ứng cử viên cho bộ sưu tập nhanh (er).

Brad Abrams entry về nó là khá rõ ràng:

Hãy xem xét một lớp học có một rất nhỏ quản lý kích thước dụ nhưng giữ một con trỏ đến một đoạn rất lớn bộ nhớ không được quản lý. Ngay cả sau khi không có ai tham chiếu đến phiên bản được quản lý, có thể vẫn hoạt động trong một thời gian vì GC chỉ xem trường hợp được quản lý kích thước không nghĩ là “đáng giá ”. Vì vậy, chúng tôi cần để “dạy” GC về chi phí thực sự của trường hợp này sao cho nó sẽ biết chính xác thời điểm khởi động bộ sưu tập để giải phóng thêm bộ nhớ trong quy trình.

+0

Thực tế, bây giờ tôi đã đọc lại bài đăng của bạn, câu hỏi của tôi vẫn đứng yên. Sau khi tôi sử dụng bitmap của mình, tôi sẽ gọi vứt bỏ nó, vì vậy nó thực sự sẽ chỉ mất 8 byte bộ nhớ. Nếu mặt khác, tôi đã không gọi vứt bỏ, tốt, sau đó nó thực sự ocuppies 2MB bộ nhớ. Có trường hợp thứ 3 của nơi không có phương pháp vứt bỏ, vì vậy GC không thể làm gì cho nó. Vì vậy, GC biết kích thước thực sự của loại sẽ chỉ giúp đỡ trong tình hình 2. Hoặc tôi thiếu một cái gì đó? –

+0

Trong trường hợp 1, bạn sẽ muốn gọi GC.AddMemoryPressure về phân bổ bitmap và sau đó GC.RemoveMemoryPressure khi bạn tự phát hành bitmap. Điều đó sẽ đảm bảo rằng đối tượng phản ánh chính xác kích thước của nó đối với GC. Tuy nhiên, nếu có một cách để đảm bảo rằng GC không bao giờ chạy trong khi đối tượng của bạn đủ điều kiện để thu thập và bitmap được cấp phát, các phương thức này có thể không quan trọng. –

+0

Vâng, trong trường hợp một, tôi có thể làm điều đó, nhưng nó sẽ không tạo ra sự khác biệt lớn, vì GC sẽ không thể làm một điều về loại của tôi, nếu tôi hiểu điều này một cách chính xác: 1) Tôi muốn khai báo biến, 8 byte được quản lý, 2MB byte không được quản lý. Sau đó tôi sẽ sử dụng nó, gọi vứt bỏ, vì vậy bộ nhớ không được quản lý được giải phóng. Ngay bây giờ nó sẽ chỉ ocuppy 8 byte. Bây giờ, với đôi mắt của tôi, đã được gọi trong AddMemoryPressure và RemoveMemoryPressure bắt đầu ở cuối sẽ không có gì khác biệt. Tôi đang làm gì sai? Xin lỗi vì đã anoying về điều này. –

2

Đặt theo cách này, vẫn giả định 8 byte đối tượng được quản lý từng đề cập đến hình ảnh không được quản lý 2 MB. GC có thể chờ đợi một thời gian dài trước khi thu thập hàng trăm hoặc hàng ngàn đối tượng được quản lý nhỏ, bởi vì chúng quá nhỏ. Điều đó có nghĩa là hàng trăm hoặc hàng nghìn khối không được quản lý liên kết 2 MB sẽ vẫn còn sống, đang chờ xóa. Điều đó có thể trở thành một vấn đề lớn. Bằng cách thêm 2 MB dung lượng bộ nhớ trong hàm tạo, bạn sẽ làm cho GC nghĩ rằng đối tượng được quản lý không phải là 8 byte lớn mà là 8 byte + 2 MB. Điều đó sẽ kích hoạt cách thu thập sớm hơn.

Đừng quên Xóa cuộc gọi.

Tất nhiên nếu bạn vứt bỏ bản thân thì bạn sẽ không cần tất cả những điều đó.

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