Finalizer ไม่ถูกเรียกหลังจาก GC.Collect () [ซ้ำ]
ฉันคิดว่าฉันขาดอะไรพื้นฐานและหวังว่าคุณจะช่วยได้ ด้านล่างโค้ดจะสร้างอ็อบเจกต์ลบการอ้างอิงและเรียกตัวรวบรวมขยะ ความคาดหวังของฉันคือ Finalizer ของ SomeClass จะถูกเรียกเมื่อยืนอยู่ใน Readline มันไม่ ฉันได้ลองโทรหา GC แล้วรวบรวมในลูปเพิ่มการโทร Sleep () เพื่อให้เธรดสุดท้ายเริ่มต้น ไม่เกิดขึ้น
เฉพาะเมื่อ Main จบลงเครื่องสุดท้ายจะถูกตี แต่น่าแปลกใจที่มันถูกตีสองครั้ง ฉันขาดอะไรไป?
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();
}
}
ภาคผนวกมีความแตกต่างในการรันโปรแกรมในโหมดดีบักกับโหมดรีลีส โปรแกรมด้านล่างผลิตในโหมดการแก้ปัญหาในขณะที่ในโหมดการเปิดตัวการแสดงStart - Done - Finalize
logfile Start - Finalize - Done
อย่างหลังคือสิ่งที่ฉันคาดหวัง
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");
}
}
คำตอบ
อ็อบเจ็กต์ที่ถูกรวบรวมเป็นขยะเหมาะสำหรับการสรุปและวางบนคิวการสรุป อย่างมีการรับประกันว่า finalizers ผู้ที่เคยไปทำงานไม่มี
ฉันจะเปลี่ยนเส้นทางคุณไปยังโพสต์ดีๆจาก Eric Lippert เกี่ยวกับเรื่องนี้ซึ่งเรียกว่า"เมื่อทุกสิ่งที่คุณรู้ไม่ถูกต้อง" โดยเฉพาะอย่างยิ่ง:
ความเชื่อ: การตั้งค่าตัวแปรเป็น null ทำให้โปรแกรมสุดท้ายทำงานบนวัตถุที่ก่อนหน้านี้อ้างถึงโดยตัวแปร การตั้งค่าตัวแปรเป็น null ไม่ได้ทำให้อะไรเกิดขึ้นทันทียกเว้นการเปลี่ยนค่าของตัวแปร หากตัวแปรเป็นการอ้างอิงที่มีชีวิตสุดท้ายของวัตถุที่เป็นปัญหาความจริงนั้นจะถูกค้นพบเมื่อตัวรวบรวมขยะเรียกใช้ตัวรวบรวมสำหรับรุ่นใดก็ตามที่วัตถุนั้นอยู่ (ถ้ามันทำงานเลยซึ่งมันอาจไม่มีการรับประกัน ที่ GC ทำงาน)
และแม้กระทั่งกับGC.Collect()
:
ตำนาน: การโทร
GC.Collect()
ทำให้ Finalizers ทำงาน ไม่ได้ทำให้คอลเล็กชันเกิดขึ้น ซึ่งอาจระบุอ็อบเจ็กต์ที่เป็นตัวเลือกสำหรับการสรุปผล แต่ไม่ได้บังคับให้จัดกำหนดการ หากนั่นคือสิ่งที่คุณต้องการ - เพื่อการทดสอบเท่านั้นโปรด! - แล้วโทรGC.WaitForPendingFinalizers()
.
GC.WaitForPendingFinalizers()
ดังนั้นโอกาสที่ดีที่สุดของความสำเร็จคือมี แต่ถึงอย่างนั้นหมายถึงคุณกับส่วนที่เหลือของโพสต์ ( และผลสืบเนื่อง ) finalizers ไม่รับประกันในการเรียกใช้ อย่าขึ้นอยู่กับว่า
ฉันเขียนคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับคำถามนี้เพื่อให้คุณสามารถใช้เป็นจุดเริ่มต้นในการค้นคว้าเพิ่มเติม