Finalizer không được gọi sau GC.Collect () [trùng lặp]
Tôi nghĩ rằng tôi đang thiếu một cái gì đó cơ bản và mong bạn có thể giúp đỡ. Đoạn mã dưới đây tạo một đối tượng, xóa tham chiếu và gọi trình thu gom rác. Kỳ vọng của tôi là trình hoàn thiện của SomeClass sẽ được gọi khi đứng trong Readline. Nó không. Tôi đã thử gọi GC.Collect trong một vòng lặp, thêm một số lệnh gọi Sleep () để bắt đầu chuỗi trình hoàn thiện. Không xảy ra.
Chỉ khi Main kết thúc trận cuối cùng mới được đánh, nhưng đáng ngạc nhiên là nó bị đánh hai lần. Tôi đang thiếu cái gì?
class Program
{
public static void Main(string[] args)
{
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done");
Console.ReadLine();
}
}
class SomeClass
{
string ss;
public SomeClass(string s) { ss = s; }
~SomeClass()
{
var hash = this.GetHashCode();
}
}
Phụ lục Có sự khác biệt trong việc chạy chương trình ở chế độ gỡ lỗi so với chế độ phát hành. Chương trình bên dưới tạo ra ở chế độ gỡ lỗi Start - Done - Finalize
trong khi ở chế độ phát hành, tệp nhật ký hiển thị Start - Finalize - Done
. Sau đó là những gì tôi mong đợi.
class Program
{
private static string logfile = @"c:\temp\log.txt";
public static void Main(string[] args)
{
File.WriteAllText(logfile, "Start\n");
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
File.AppendAllText(logfile, "Done\n");
}
}
class SomeClass
{
private static string logfile = @"c:\temp\log.txt";
public string SomeString { get; set; }
public SomeClass(string s) { SomeString = s; }
~SomeClass()
{
File.AppendAllText(logfile, "Finalize\n");
}
}
Trả lời
Các đối tượng được thu gom rác trở nên phù hợp để hoàn thiện và được đưa vào hàng đợi hoàn thiện. Hoàn toàn không có gì đảm bảo rằng những bản hoàn thiện đó sẽ chạy .
Tôi sẽ chuyển hướng bạn đến các bài đăng tuyệt vời từ Eric Lippert về vấn đề này, được gọi là "Khi mọi thứ bạn biết đều sai." Đặc biệt:
Lầm tưởng: Đặt một biến thành null sẽ làm cho trình hoàn thiện chạy trên đối tượng đã được tham chiếu trước đó bởi biến. Đặt một biến thành null không gây ra bất kỳ điều gì xảy ra ngay lập tức ngoại trừ việc thay đổi giá trị của biến. Nếu biến là tham chiếu sống động cuối cùng đến đối tượng được đề cập thì sự thật đó sẽ được phát hiện khi bộ thu gom rác chạy bộ thu thập cho bất kỳ thế hệ nào mà đối tượng đã ở trong đó. (Nếu nó chạy ở tất cả, thì có thể không. Không có gì đảm bảo mà GC chạy.)
Và ngay cả với GC.Collect()
:
Lầm tưởng: Việc gọi
GC.Collect()
khiến trình hoàn thiện chạy. Không, nó gây ra một bộ sưu tập xảy ra. Điều đó có thể xác định các đối tượng là ứng cử viên để hoàn thiện, nhưng nó không bắt buộc phải lên lịch cho luồng hoàn thiện. Nếu đó là những gì bạn muốn - chỉ cho mục đích thử nghiệm! - rồi gọiGC.WaitForPendingFinalizers()
.
Vì vậy, cơ hội thành công tốt nhất là với GC.WaitForPendingFinalizers()
. Nhưng ngay cả sau đó, giới thiệu bạn đến phần còn lại của bài đăng ( và phần tiếp theo của nó ), NGƯỜI KẾT THÚC KHÔNG ĐƯỢC BẢO ĐẢM CHẠY . Đừng phụ thuộc vào điều đó.
Tôi đã viết một lời giải thích chi tiết hơn về câu hỏi này để bạn có thể sử dụng nó như một điểm khởi đầu để nghiên cứu thêm.