Tôi đã nghĩ viết một chương trình demo nhỏ thể hiện sự khác biệt. Hóa ra hơi khó khăn hơn tôi đếm. Thành phần cần thiết đầu tiên là để đảm bảo rằng chuỗi finalizer có thể được làm chậm lại để bạn có thể quan sát giá trị của WeakReference.IsAlive mà không có nguy cơ bị ảnh hưởng bởi một cuộc đua với thread finalizer.Vì vậy, tôi đã sử dụng:
class FinalizerDelayer {
~FinalizerDelayer() {
Console.WriteLine("Delaying finalizer...");
System.Threading.Thread.Sleep(500);
Console.WriteLine("Delay done");
}
}
Sau đó một chút lớp đó sẽ là mục tiêu của WeakReference:
class Example {
private int instance;
public Example(int instance) { this.instance = instance; }
~Example() {
Console.WriteLine("Example {0} finalized", instance);
}
}
Sau đó, một chương trình thể hiện sự khác biệt giữa một dài và một tham chiếu yếu ngắn:
class Program {
static void Main(string[] args) {
var target1 = new Example(1);
var target2 = new Example(2);
var shortweak = new WeakReference(target1);
var longweak = new WeakReference(target2, true);
var delay = new FinalizerDelayer();
GC.Collect(); // Kills short reference
Console.WriteLine("Short alive = {0}", shortweak.IsAlive);
Console.WriteLine("Long alive = {0}", longweak.IsAlive);
GC.WaitForPendingFinalizers();
Console.WriteLine("Finalization done");
GC.Collect(); // Kills long reference
Console.WriteLine("Long alive = {0}", longweak.IsAlive);
Console.ReadLine();
}
}
Bạn phải chạy chương trình này để trình gỡ lỗi không thể ảnh hưởng đến thời gian sống của các đối tượng. Chọn bản phát hành Bản phát hành và thay đổi cài đặt trình gỡ lỗi: Công cụ + Tùy chọn, Gỡ lỗi, Chung, bỏ chọn tùy chọn "Loại bỏ tối ưu hóa JIT".
Đã tắt thứ tự hoàn thành của các đối tượng thực sự là không xác định. Thứ tự là khác nhau mỗi khi bạn chạy chương trình. Chúng tôi muốn đối tượng FinalizerDelayer được hoàn thành trước nhưng điều đó không phải lúc nào cũng xảy ra. Tôi nghĩ rằng là một tác dụng phụ đối với tính năng Random Space Layout được tích hợp sẵn, nó làm cho mã được quản lý rất khó tấn công. Nhưng chạy nó thường đủ và cuối cùng bạn sẽ nhận được:
Trì hoãn finalizer ...
ngắn sống = False
dài sống = True
trễ thực hiện
Ví dụ 1 hoàn
Ví dụ 2 hoàn
Quyết toán thực hiện
dài sống = False
câu chuyện dài ngắn:
- Một ngắn bộ tài liệu tham khảo yếu IsAlive để sai ngay khi đối tượng được thu thập và được đặt trên hàng đợi freachable, sẵn sàng cho nó được hoàn thành. Đối tượng vẫn tồn tại về mặt vật lý nhưng không có tham chiếu mạnh nào tồn tại nữa, nó sẽ sớm được hoàn thành.
- Một tham chiếu dài yếu theo dõi đối tượng suốt quãng thời gian thực của cuộc đời, kể cả cuộc sống của nó trên hàng đợi có thể xử lý được. IsAlive sẽ không được đặt thành false cho đến khi trình hoàn tất của nó hoàn tất.
Cẩn thận với một quirk khi đối tượng được phục hồi, di chuyển trở lại từ hàng đợi có thể xử lý sang vùng thông thường khi tham chiếu mạnh được tạo lại. Không phải cái gì tôi đã khám phá trong chương trình demo này, nhưng cần phải có một tham chiếu dài yếu để quan sát điều đó. Lý do cơ bản tại sao bạn cần một tham chiếu dài yếu.
Wow, đó là tài liệu khó hiểu ... nó * trông * giống như tài liệu tham chiếu yếu ngắn nên nói về quyết toán, chứ không phải thu gom rác - nhưng không rõ. –
Tôi đã xem xét mã nguồn SSCLI cũ để thử xem những gì tôi có thể tìm thấy.Đã không tìm thấy bất cứ điều gì rõ ràng nhưng đã tìm thấy một bình luận hấp dẫn bên trong 'Mục tiêu 'getter:" Chỉ nên xảy ra khi sử dụng bất hợp pháp, như sử dụng một WeakReference từ finalizer "- vì vậy có lẽ những gì bạn đang cố gắng làm là cam chịu anyway. –
Không phải là câu trả lời nhưng đáng lưu ý rằng bạn nên tránh phá hủy và điều này rất có thể là vấn đề XY. –