ใน. NET ฉันควรใช้ภายใต้สถานการณ์GC.SuppressFinalize()
ใด
การใช้วิธีนี้ทำให้ฉันได้เปรียบอะไร
ใน. NET ฉันควรใช้ภายใต้สถานการณ์GC.SuppressFinalize()
ใด
การใช้วิธีนี้ทำให้ฉันได้เปรียบอะไร
คำตอบ:
SuppressFinalize
ควรถูกเรียกโดยคลาสที่มี finalizer เท่านั้น กำลังแจ้ง Garbage Collector (GC) ว่าthis
มีการล้างวัตถุอย่างสมบูรณ์
IDisposable
รูปแบบที่แนะนำเมื่อคุณมี finalizer คือ:
public class MyClass : IDisposable
{
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// called via myClass.Dispose().
// OK to use any private object references
}
// Release unmanaged resources.
// Set large fields to null.
disposed = true;
}
}
public void Dispose() // Implement IDisposable
{
Dispose(true);
GC.SuppressFinalize(this);
}
~MyClass() // the finalizer
{
Dispose(false);
}
}
โดยปกติ CLR จะเก็บแท็บบนวัตถุด้วยตัวสร้างขั้นสุดท้ายเมื่อมันถูกสร้างขึ้น (ทำให้มีราคาแพงกว่าในการสร้าง) SuppressFinalize
บอก GC ว่าวัตถุได้รับการทำความสะอาดอย่างถูกต้องและไม่จำเป็นต้องไปยังคิวสุดท้าย ดูเหมือนว่า destructor ของ C ++ แต่ไม่ได้ทำอะไรคล้าย ๆ กัน
การSuppressFinalize
เพิ่มประสิทธิภาพนั้นไม่สำคัญเพราะวัตถุของคุณสามารถใช้งานได้นานรอคิว finalizer อย่าล่อลวงให้โทรหาSuppressFinalize
วัตถุอื่นในใจคุณ นั่นเป็นข้อบกพร่องร้ายแรงที่รอให้เกิดขึ้น
แนวทางการออกแบบแจ้งให้เราทราบว่าไม่จำเป็นต้องใช้เครื่องมือปรับแต่งขั้นสุดท้ายหากวัตถุของคุณใช้IDisposable
แต่ถ้าคุณมีเครื่องมือสร้างขั้นสุดท้ายคุณควรใช้IDisposable
เพื่ออนุญาตให้การล้างข้อมูลในชั้นเรียนของคุณเป็นไปอย่างราบรื่น
ส่วนใหญ่เวลาที่คุณควรจะได้รับไปด้วยIDisposable
เพื่อล้างทรัพยากร คุณควรต้องมีเครื่องมือขั้นสุดท้ายเมื่อวัตถุของคุณเก็บทรัพยากรที่ไม่มีการจัดการไว้เท่านั้นและคุณต้องรับประกันว่าทรัพยากรเหล่านั้นได้รับการทำความสะอาดแล้ว
หมายเหตุ: บางครั้งผู้ทำโคเดอร์จะเพิ่ม finalizer เพื่อตรวจแก้จุดบกพร่องการสร้างIDisposable
คลาสของตนเองเพื่อทดสอบว่ารหัสกำจัดIDisposable
วัตถุอย่างเหมาะสม
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif
IDisposable
ไม่ได้sealed
แล้วมันควรจะรวมถึงการเรียกร้องให้GC.SuppressFinalize(this)
ถึงแม้ว่ามันจะไม่รวมถึง finalizer นี่เป็นสิ่งจำเป็นเพื่อให้แน่ใจว่าความหมายที่ถูกต้องสำหรับประเภทที่ได้รับซึ่งเพิ่ม finalizer ที่ผู้ใช้กำหนด แต่จะแทนที่เฉพาะDispose(bool)
วิธีที่ได้รับการป้องกัน
sealed
กล่าวถึงโดย @SamHarwell เป็นสิ่งสำคัญสำหรับคลาสที่ได้รับ ผลการ CodeAnalysis ใน ca1816 ca1063 + เมื่อเรียนไม่ได้ปิดผนึก SuppressFinalize
แต่การเรียนที่ปิดสนิทโดยไม่ต้องมีการปรับ
SupressFinalize
แจ้งให้ระบบทราบว่าสิ่งใดก็ตามที่จะต้องทำใน Finalizer นั้นเสร็จสิ้นแล้วดังนั้น Finalizer จึงไม่จำเป็นต้องถูกเรียก จาก. NET docs:
วัตถุที่ใช้อินเทอร์เฟซ IDisposable สามารถเรียกวิธีนี้จากนั้น IDisposable.Dispose วิธีการเพื่อป้องกันการเก็บขยะจากการเรียก Object.Finalize บนวัตถุที่ไม่ต้องการ
โดยทั่วไปแล้วDispose()
วิธีการส่วนใหญ่ควรจะสามารถโทรGC.SupressFinalize()
ได้เพราะมันควรจะล้างข้อมูลทุกอย่างที่จะต้องทำความสะอาดใน Finalizer
SupressFinalize
เป็นเพียงสิ่งที่ให้การเพิ่มประสิทธิภาพที่ช่วยให้ระบบไม่รบกวนการจัดคิววัตถุไปยังเธรด finalizer ที่เขียนถูกต้องDispose()
/ finalizer GC.SupressFinalize()
ควรทำงานอย่างถูกต้องโดยมีหรือไม่มีการเรียกไปยัง
ต้องเรียกใช้Dispose
เมธอดนั้นกับวิธีการของออบเจ็กต์ที่ใช้งานIDisposable
ด้วยวิธีนี้ GC จะไม่เรียก Finalizer อีกครั้งหากมีคนเรียกDispose
เมธอด
Dispose(true);
GC.SuppressFinalize(this);
หากวัตถุมี finalizer, .net ใส่การอ้างอิงในคิวการสรุป
เนื่องจากเรามีการโทรDispose(ture)
เป็นวัตถุที่ชัดเจนดังนั้นเราจึงไม่ต้องการคิวการสรุปเพื่อทำงานนี้
ดังนั้นการโทรGC.SuppressFinalize(this)
ลบการอ้างอิงในคิวการสรุป
ถ้าชั้นเรียนหรืออะไรที่ได้มาจากมันอาจถืออ้างอิงสดที่ผ่านมาเพื่อวัตถุที่มี finalizer แล้วอย่างใดอย่างหนึ่งGC.SuppressFinalize(this)
หรือGC.KeepAlive(this)
ควรจะเรียกว่าบนวัตถุหลังจากการดำเนินการใด ๆ ที่อาจได้รับผลกระทบโดย finalizer ว่าจึงมั่นใจได้ว่าวอน finalizer ไม่ทำงานจนกว่าจะเสร็จสิ้นการดำเนินการ
ค่าใช้จ่ายของGC.KeepAlive()
และGC.SuppressFinalize(this)
เป็นหลักเหมือนกันในคลาสใด ๆ ที่ไม่มี finalizer และคลาสที่มี finalizers ควรเรียกโดยทั่วไปGC.SuppressFinalize(this)
ดังนั้นการใช้ฟังก์ชันหลังเนื่องจากขั้นตอนสุดท้ายของDispose()
อาจไม่จำเป็นเสมอไป แต่จะไม่จำเป็น จะผิด.