2012-01-27 13 views
5

This bài viết nóiTại sao các lớp học với finalizers cần nhiều hơn một chu kỳ thu gom rác thải?

Nếu một đối tượng có một finalizer, nó không phải là ngay lập tức bị loại bỏ khi các nhà sưu tập rác quyết định nó không còn ‘sống’. Thay vào đó, nó sẽ trở thành một loại đặc biệt của root cho đến khi .NET đã gọi phương thức finalizer. Điều này có nghĩa là các đối tượng này thường yêu cầu nhiều hơn một bộ sưu tập rác sẽ bị xóa khỏi bộ nhớ vì chúng sẽ tồn tại trong thời gian đầu tiên mà chúng không được sử dụng.

Câu hỏi của tôi là tại sao GC không gọi finalizer khi tìm thấy đối tượng đó không thể được tham chiếu nữa và thu thập đối tượng ngay lập tức? tại sao nó cần nhiều hơn vào bộ sưu tập rác?

Trả lời

6

Hai điểm cần cân nhắc:

  • Các finalizer có thể mất một thời gian để hoàn thành. Ví dụ, nó có thể kết thúc đóng một nguồn tài nguyên hoặc một cái gì đó tương tự. Bạn sẽ không muốn rằng đó là một phần của thời gian thu gom rác, mà có thể ngăn chặn các chủ đề từ làm việc (khi họ chỉ muốn nhận được một số bộ nhớ). Bằng cách chạy hoàn thành một cách riêng biệt, bản thân GC có thể hoàn thành rất nhanh, và công việc hoàn thành có thể được thực hiện song song với các công việc khác sau này.

  • Trình hoàn thiện có thể hồi sinh đối tượng bằng cách hiển thị lại lần nữa - nhưng phát hiện (tôi nghi ngờ) yêu cầu quét bộ nhớ khác ... vậy tại sao không chỉ đợi đến lần tiếp theo?

3

Vì (tùy thuộc vào chế độ GC được chọn) khi đang thực hiện GC it has to pause key parts of the runtime. Do đó bạn muốn điều này càng nhanh càng tốt. Điều này tạo ra hai vấn đề:

  1. nó không biết bao lâu finalizer sẽ thực hiện để chạy (mặc dù nó có một giới hạn cứng), và không muốn trì hoãn khôi phục thời gian chạy
  2. runtime cần được chạy cho finalizer để làm việc đáng tin cậy (ngay cả khi a thread GC được sử dụng, mã bạn viết hình dung có thể quan tâm đến chủ đề khác)

để giải quyết cả hai vấn đề này, những người có finalizers cấp phát đang xếp hàng đợi, và sau đó thực hiện sau GC đã kết thúc (khi thời gian chạy hoạt động).

Như một lưu ý phụ, cách tốt nhất là kết hợp các finalizers với IDisposable và hủy Dispose() hủy quyết toán; theo cách đó, nó không cần phải hoàn thành sau đó và được dọn sạch trong một bước.

0

Khi .net rác-thu chạy, các đối tượng được chia thành ba loại: đối tượng mà có thể truy cập từ một tham chiếu bắt nguồn từ "bình thường", các đối tượng mà không thể truy cập bởi bất kỳ tham khảo rooted, và các đối tượng mà không thể truy cập được bằng bất kỳ tham chiếu gốc "bình thường" nào, nhưng có yêu cầu nhận thông báo khi chúng bị bỏ rơi, hoặc có thể truy cập được từ các đối tượng khác đã thực hiện như vậy. Bộ gom rác tạo danh sách các đối tượng trong danh mục thứ ba đó; danh sách đó được lưu trữ như là một tham chiếu bắt nguồn, làm cho tất cả các đối tượng trong nó 'sống'.Tuy nhiên, hệ thống đi qua các mục trong danh sách đó, hủy bỏ các yêu cầu 'thông báo' của họ, chạy phương thức Finalize() của họ và loại bỏ chúng khỏi danh sách. Nếu không có tham chiếu đến đối tượng tồn tại bất cứ nơi nào một khi tất cả những gì được nói và thực hiện, sau đó đối tượng sẽ được tuyên bố "chết" trên chu kỳ GC tiếp theo.

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