Di .NET, dalam kondisi apa saya harus menggunakan GC.SuppressFinalize()
?
Apa keuntungan yang diberikan metode ini kepada saya?
Di .NET, dalam kondisi apa saya harus menggunakan GC.SuppressFinalize()
?
Apa keuntungan yang diberikan metode ini kepada saya?
Jawaban:
SuppressFinalize
seharusnya hanya dipanggil oleh kelas yang memiliki finalizer. Ini menginformasikan kepada Pengumpul Sampah (GC) bahwa this
objek telah dibersihkan sepenuhnya.
IDisposable
Pola yang disarankan ketika Anda memiliki finalizer adalah:
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);
}
}
Biasanya, CLR menyimpan tab pada objek dengan finalizer ketika mereka dibuat (membuatnya lebih mahal untuk dibuat). SuppressFinalize
memberi tahu GC bahwa objek telah dibersihkan dengan benar dan tidak perlu masuk ke antrian finalizer. Itu terlihat seperti destruktor C ++, tetapi tidak bertindak seperti itu.
The SuppressFinalize
optimasi tidak sepele, sebagai obyek Anda dapat hidup lama menunggu di antrian finalizer. Jangan tergoda untuk memanggil SuppressFinalize
benda lain, ingatlah Anda. Itu cacat serius menunggu untuk terjadi.
Pedoman desain memberi tahu kami bahwa finalizer tidak diperlukan jika objek Anda diimplementasikan IDisposable
, tetapi jika Anda memiliki finalizer, Anda harus mengimplementasikannyaIDisposable
untuk memungkinkan pembersihan deterministik kelas Anda.
Sebagian besar waktu Anda harus bisa lolos IDisposable
membersihkan sumber daya. Anda hanya perlu finalizer ketika objek Anda memegang sumber daya yang tidak dikelola dan Anda perlu memastikan sumber daya tersebut dibersihkan.
Catatan: Terkadang coders akan menambahkan finalizer ke debug build dari IDisposable
kelas mereka sendiri untuk menguji kode yang telah membuang IDisposable
objek mereka dengan benar.
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif
IDisposable
tidak sealed
, maka harus menyertakan panggilan GC.SuppressFinalize(this)
bahkan jika itu tidak termasuk finalizer yang ditentukan pengguna . Ini diperlukan untuk memastikan semantik yang tepat untuk tipe turunan yang menambahkan finalizer yang ditentukan pengguna tetapi hanya menimpa Dispose(bool)
metode yang dilindungi .
sealed
seperti yang disebutkan oleh @SamHarwell adalah penting, untuk kelas turunan. Hasil CodeAnalysis di ca1816 + ca1063 ketika kelas tidak disegel, tetapi kelas disegel baik-baik saja tanpa SuppressFinalize
.
SupressFinalize
memberitahu sistem bahwa pekerjaan apa pun yang telah dilakukan di finalizer telah dilakukan, sehingga finalizer tidak perlu dipanggil. Dari .NET docs:
Objek yang mengimplementasikan antarmuka IDisposable dapat memanggil metode ini dari metode IDisposable.Dispose untuk mencegah pengumpul sampah memanggil Object.Finalize pada objek yang tidak memerlukannya.
Secara umum, hampir semua Dispose()
metode harus dapat memanggil GC.SupressFinalize()
, karena itu harus membersihkan segala sesuatu yang akan dibersihkan di finalizer.
SupressFinalize
hanyalah sesuatu yang menyediakan optimasi yang memungkinkan sistem untuk tidak repot mengantri objek ke thread finalizer. Seorang Dispose()
finalizer yang ditulis dengan benar harus bekerja dengan baik dengan atau tanpa panggilan GC.SupressFinalize()
.
Metode itu harus dipanggil pada Dispose
metode objek yang mengimplementasikan IDisposable
, dengan cara ini GC tidak akan memanggil finalizer lain kali jika seseorang memanggilDispose
metode tersebut.
Lihat: Metode GC.SuppressFinalize (Obyek) - Microsoft Documents
Dispose(true);
GC.SuppressFinalize(this);
Jika objek memiliki finalizer, .net menaruh referensi dalam antrian finalisasi.
Karena kita memiliki panggilan Dispose(ture)
, itu jelas objek, jadi kita tidak perlu antrian finalisasi untuk melakukan pekerjaan ini.
Jadi panggilan GC.SuppressFinalize(this)
hapus referensi dalam antrian finalisasi.
Jika suatu kelas, atau sesuatu yang diturunkan darinya, mungkin memiliki referensi langsung terakhir ke objek dengan finalizer, maka salah satu GC.SuppressFinalize(this)
atauGC.KeepAlive(this)
harus dipanggil pada objek setelah operasi apa pun yang mungkin terpengaruh oleh finalizer itu, sehingga memastikan bahwa finalizer menang. dapat berjalan sampai setelah operasi itu selesai.
Biaya GC.KeepAlive()
dan GC.SuppressFinalize(this)
pada dasarnya sama di setiap kelas yang tidak memiliki finalizer, dan kelas yang memiliki finalizer umumnya harus memanggil GC.SuppressFinalize(this)
, jadi menggunakan fungsi yang terakhir sebagai langkah terakhir Dispose()
mungkin tidak selalu diperlukan, tetapi tidak akan diperlukan. salah