GC.SuppressFinalize () ne zaman kullanmalıyım?


287

.NET'te hangi koşullar altında kullanmalıyım GC.SuppressFinalize()?

Bu yöntemi kullanmamın bana sağladığı avantajlar nelerdir?


Finalizörler ve IDisposable hakkında birkaç soru gördüm, stackoverflow da GC.SupressFinalize ve zayıf referanslar hakkında bir şey olmalı
Sam Saffron

Zayıf referansların finalizörlerle ilgili hiçbir şey yapmadığını düşünmüyorum - belki onlar hakkında daha doğrudan bir soru göndermelisiniz.
Michael Burr

Yerp I, zayıf referanslar hakkında ayrı bir soru yayınlamak anlamına geliyordu, nesne havuzları inşa ettiğinizde bunların hepsi birbirine bağlanabilir. Ayrıca nesne canlanması ala hakkında bir soru sormalıyız ReRegisterForFinalize
Sam Saffron

Yanıtlar:


296

SuppressFinalizeyalnızca sonlandırıcısı olan bir sınıf tarafından çağrılmalıdır. Çöp Toplayıcısına (GC) şunu bildiriyor:this nesnenin tamamen temizlendiğini .

IDisposableSonlandırıcınız olduğunda önerilen kalıp:

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);
    }
}

Normalde, CLR, oluşturulduklarında sonlandırıcı içeren nesneler üzerindeki sekmeleri tutar (bunları oluşturmak daha pahalı hale getirir). SuppressFinalizeGC'ye nesnenin düzgün bir şekilde temizlendiğini ve sonlandırıcı kuyruğuna gitmesi gerekmediğini bildirir. Bir C ++ yıkıcıya benziyor, ancak bir şey gibi davranmıyor.

SuppressFinalizeNesnelerinizin sonlandırıcı kuyrukta bekleyen uzun bir süre yaşayabilir olarak optimizasyon, önemsiz değildir. Aramaya cazip gelmeSuppressFinalizeAklınıza gelen diğer nesneleri . Bu, gerçekleşmeyi bekleyen ciddi bir kusur.

Tasarım yönergeleri, nesneniz uygulanırsa bir sonlandırıcının gerekli olmadığını bildirir IDisposable, ancak bir sonlandırıcınız varsa,IDisposable , sınıfınızın deterministik olarak temizlenmesine izin vermek için .

Çoğu zaman kaçabilmeniz gerekir IDisposable kaynakları temizlemek . Bir sonlandırıcıya yalnızca nesneniz yönetilmeyen kaynaklara bağlı olduğunda ve bu kaynakların temizlendiğinden emin olmanız gerektiğinde sonlandırmaya ihtiyacınız vardır.

Not: Bazen kodlayıcılar, IDisposablekodun IDisposablenesnelerini düzgün bir şekilde bertaraf ettiğini test etmek için kendi sınıflarının yapılarındaki hata ayıklama işlemlerine bir sonlandırıcı ekler .

public void Dispose() // Implement IDisposable
{
    Dispose(true);
#if DEBUG
    GC.SuppressFinalize(this);
#endif
}

#if DEBUG
~MyClass() // the finalizer
{
    Dispose(false);
}
#endif

1
İlk kod snippet'inde sadece önerilen IDisposable + finalizer deseninin neye benzediğini gönderiyorum. Hata ayıklama kodu iyidir, ancak dikkat dağıtıcı olabilir. ..Yönetimsiz kaynaklara sahip sınıflar dışında finalizörlerden kaçınmayı tavsiye ederim. Güvenli sonlandırıcı kod yazmak önemsizdir.
Robert Paulson

1
Merhaba, Niçin sonlandırıcıdan parametre olarak false ile false değerini çağırmamız gerekiyor? Ya imha hiç çağrılmadıysa ve imha etmeyecekse? Ya sadece nesnenin atılıp atılmadığını kontrol edersek ve gerçek temizliği yaparsak.
Hayalperest

3
@Dreamer - uygulamanıza bağlıdır. Genel olarak Dispose'in sonlandırıcı tarafından IDisposable.Dispose () uygulamasına karşı çağrılıp çağrılmadığını bilmek istersiniz. Sonlandırıcıdan çağrılırsa, özel referansların artık geçerli olmadığını ve gerçekten fazla bir şey yapamayacağınızı varsaymalısınız. Ancak IDisposable.Dispose () 'den çağrılırsa, referansların hala geçerli olduğunu bilirsiniz.
Robert Paulson

32
Sınıf uygulaması IDisposabledeğilse sealed, GC.SuppressFinalize(this) kullanıcı tanımlı bir sonlandırıcı içermese bile çağrıyı içermelidir . Bu, kullanıcı tanımlı bir sonlandırıcı ekleyen ancak yalnızca korunan Dispose(bool)yöntemi geçersiz kılan türetilmiş türler için uygun semantik sağlamak için gereklidir .
Sam Harwell

1
Olmak değil sealedolarak @SamHarwell tarafından bahsedilen türetilmiş sınıfları için, önemlidir. CodeAnalysis, sınıf mühürlenmediğinde ca1816 + ca1063 ile sonuçlanır, ancak kapalı sınıflar olmadan iyidir SuppressFinalize.
dashesy

38

SupressFinalizesisteme sonlandırıcıda yapılacak her türlü işin zaten yapıldığını söyler, bu yüzden sonlandırıcının çağrılmasına gerek yoktur. .NET belgelerinden:

IDisposable arabirimini uygulayan nesneler, çöp toplayıcının, bunu gerektirmeyen bir nesne üzerinde Object.Finalize öğesini çağırmasını önlemek için bu yöntemi IDisposable.Dispose yönteminden çağırabilir.

Genel olarak, herhangi bir Dispose()yöntemin çoğuGC.SupressFinalize() , çünkü sonlandırıcıda temizlenecek her şeyi temizlemelidir.

SupressFinalizesadece sistemin nesneyi sonlandırıcı iş parçacığına kuyruğa almamasına izin veren bir optimizasyon sağlayan bir şeydir. Düzgün yazılmış Dispose()/ sonlandırıcı çağrılı olsun veya olmasın düzgün çalışmalıdır GC.SupressFinalize().


2

Bu yöntem, bu Disposeyöntemi uygulayan nesneler yönteminde çağrılmalıdır, IDisposablebu şekilde birileri Disposeyöntemi çağırdığında GC sonlandırıcıyı başka bir kez çağırmaz .

Bkz. GC.SuppressFinalize (Object) Yöntemi - Microsoft Belgeleri


9
Bence "Zorunlu" yanlış - hatta "gerekir" - Sadece bazı senaryolarda, kuyruk / sonlandırma yükünü ortadan kaldırabilirsiniz.
Temel

1
Dispose(true);
GC.SuppressFinalize(this);

Nesnede sonlandırıcı varsa, .net sonlandırma kuyruğuna bir başvuru koydu.

Çağrı yaptığımızdan Dispose(ture), bu nesneyi temizlediğinden, bu işi yapmak için sonlandırma sırasına ihtiyacımız yok.

Bu yüzden GC.SuppressFinalize(this)sonlandırma kuyruğundaki kaldır referansını çağırın .


0

Bir sınıf veya bundan türetilen herhangi bir şey, bir sonlandırıcıya sahip bir nesneye son canlı referansı tutabilirse, o sonlandırıcıdan olumsuz etkilenebilecek herhangi bir işlemden sonra nesneye ya GC.SuppressFinalize(this)da GC.KeepAlive(this)çağrılmalı, böylece sonlandırıcının kazandığından emin olunmalıdır. bu işlem tamamlanıncaya kadar çalıştırılmaz.

Sonlandırıcı olmayan herhangi bir sınıfın maliyeti GC.KeepAlive()ve GC.SuppressFinalize(this)esas olarak aynıdır ve sonlandırıcıları olan sınıflar genellikle çağırmalıdır GC.SuppressFinalize(this), bu nedenle son işlevi olarak sonuncu işlev olarak kullanmak Dispose()her zaman gerekli olmayabilir, ancak olmayacaktır. yanlış olmak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.