मुझे GC.SuppressFinalize () का उपयोग कब करना चाहिए?


287

.NET में, मुझे किन परिस्थितियों में उपयोग करना चाहिए GC.SuppressFinalize()?

इस पद्धति का उपयोग करने से मुझे क्या लाभ है?


मैंने फाइनलीज़ और आईडीसोपायरी के बारे में कुछ प्रश्न देखे हैं, स्टैकओवरफ़्लो में GC.SupressFinalize और कमजोर संदर्भों के बारे में भी कुछ होना चाहिए
सैम केसर

मुझे नहीं लगता कि कमजोर संदर्भ फाइनल करने वालों के बारे में कुछ भी करते हैं - शायद आपको उनके बारे में अधिक प्रत्यक्ष प्रश्न पोस्ट करना चाहिए।
माइकल बूर

येरप I का अर्थ कमजोर रिफ के बारे में एक अलग प्रश्न पोस्ट करना था, यह सब आपस में जोड़ सकते हैं जब आप ऑब्जेक्ट पूल का निर्माण करते हैं। इसके अलावा मुझे वस्तु पुनरुद्धार के बारे में एक प्रश्न पूछना चाहिए ReRegisterForFinalize
सैम केसर

जवाबों:


296

SuppressFinalizeकेवल एक वर्ग द्वारा बुलाया जाना चाहिए जिसमें एक अंतिम रूप है। यह कचरा संग्रहकर्ता (जीसी) को सूचित कर रहा है कि thisवस्तु को पूरी तरह से साफ किया गया था।

IDisposableजब आपके पास अंतिम रूप हो तो अनुशंसित पैटर्न:

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

आम तौर पर, सीएलआर वस्तुओं पर एक अंतिम रूप से नज़र रखता है जब वे बनाए जाते हैं (बनाने के लिए उन्हें अधिक महंगा बनाते हैं)। SuppressFinalizeजीसी को बताता है कि ऑब्जेक्ट को ठीक से साफ किया गया था और इसे अंतिम कतार पर जाने की आवश्यकता नहीं है। यह C ++ डिस्ट्रक्टर की तरह दिखता है, लेकिन यह किसी भी चीज की तरह काम नहीं करता है।

SuppressFinalizeअनुकूलन के रूप में अपने वस्तुओं एक लंबे समय finalizer कतार पर इंतजार कर रह सकते हैं, तुच्छ नहीं है। SuppressFinalizeअन्य वस्तुओं पर कॉल करने के लिए परीक्षा मत करो तुम मन। यह एक गंभीर दोष होने की प्रतीक्षा कर रहा है।

डिज़ाइन दिशानिर्देश हमें सूचित करते हैं कि यदि आपकी वस्तु लागू होती है IDisposable, तो एक अंतिम रूप से आवश्यक नहीं है , लेकिन यदि आपके पास एक अंतिम उपकरण है तो आपको IDisposableअपनी कक्षा के निर्धारक सफाई की अनुमति देने के लिए लागू करना चाहिए ।

अधिकांश समय आपको IDisposableसंसाधनों को साफ करने में सक्षम होना चाहिए । आपको केवल एक अंतिम रूप देने वाले की आवश्यकता होनी चाहिए जब आपकी वस्तु अप्रबंधित संसाधनों पर आधारित हो और आपको उन संसाधनों को साफ करने की गारंटी देने की आवश्यकता हो।

नोट: कभी-कभी कोडर अंतिम रूप से अपने स्वयं के IDisposableवर्गों के डिबग बिल्ड में जोड़ देंगे ताकि यह परीक्षण किया जा सके कि कोड ने उनकी IDisposableवस्तु को ठीक से निपटाया है।

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

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

1
पहले कोड स्निपेट में मैं सिर्फ वही पोस्ट कर रहा हूं जो अनुशंसित आईडीसोफिल + फाइनल पैटर्न जैसा दिखता है। डिबगिंग कोड अच्छा है, लेकिन यह विचलित करने वाला हो सकता है। .. मैं केवल उन वर्गों को छोड़कर अंतिम रूप से बचने की सिफारिश कर सकता हूं जिनके पास अप्रबंधित संसाधन हैं। सुरक्षित फाइनल कोड लिखना गैर-तुच्छ है।
रॉबर्ट पॉलसन

1
नमस्ते, हमें अंतिम रूप से पैरामीटर के रूप में गलत के साथ कॉल करने की आवश्यकता क्यों है? क्या होगा अगर डिस्पोजल को कभी नहीं बुलाया गया और फिर यह डिस्पोज नहीं होगा? क्या होगा अगर हम सिर्फ इस बात की जांच करते हैं कि वस्तु का निपटान किया गया है या नहीं और वास्तविक सफाई करें।
स्वप्नदर्शी

3
@ ड्रीमर - यह आपके कार्यान्वयन पर निर्भर करता है। सामान्य तौर पर आप यह जानना चाहते हैं कि क्या डिसपोजर को IDis प्रयोज्य बनाम डिसपोजल () कार्यान्वयन द्वारा बुलाया जा रहा है। यदि अंतिम रूप से कहा जाता है, तो आपको यह मान लेना चाहिए कि निजी संदर्भ अब मान्य नहीं हैं, और आप वास्तव में बहुत कुछ नहीं कर सकते। यदि फिर भी IDisposable.Dispose () से कॉल किया जाता है, तो आप जानते हैं कि संदर्भ अभी भी मान्य हैं।
रॉबर्ट पॉलसन

32
यदि लागू करने वाला वर्ग IDisposableनहीं है sealed, तो उसे कॉल को इसमें शामिल करना चाहिए, GC.SuppressFinalize(this) भले ही उसमें उपयोगकर्ता द्वारा परिभाषित अंतिम रूप से शामिल न हो । यह व्युत्पन्न प्रकारों के लिए उचित शब्दार्थ सुनिश्चित करने के लिए आवश्यक है जो एक उपयोगकर्ता-परिभाषित फ़ाइनलीज़र जोड़ते हैं लेकिन केवल संरक्षित Dispose(bool)विधि को ओवरराइड करते हैं ।
सैम हरवेल

1
sealedव्युत्पन्न वर्गों के लिए @SamHarwell द्वारा उल्लेख नहीं किया जाना महत्वपूर्ण है। कोडएनालिसिस का परिणाम ca1816 + ca1063 होता है जब कक्षा को सील नहीं किया जाता है, लेकिन सील की गई कक्षाएं बिना ठीक होती हैं SuppressFinalize
द्वादशी

38

SupressFinalizeसिस्टम को बताता है कि फाइनल में जो भी काम किया जाएगा वह पहले ही हो चुका है, इसलिए फाइनल करने वाले को बुलाने की जरूरत नहीं है। .NET डॉक्स से:

वस्तुएं जो कि आइडीसोपायरी इंटरफ़ेस को लागू करती हैं, इस विधि को आईडीआईसोप्रेटी से कह सकते हैं। कचरा विधि से ऑब्जेक्ट को कॉल करने से रोकने के लिए विधि का उपयोग करें। ऐसी वस्तु पर जिसकी आवश्यकता नहीं होती है।

सामान्य तौर पर, किसी भी Dispose()विधि को कॉल करने में सक्षम होना चाहिए GC.SupressFinalize(), क्योंकि यह सब कुछ साफ करना चाहिए जो अंतिम रूप से साफ हो जाएगा।

SupressFinalizeबस कुछ ऐसा है जो एक अनुकूलन प्रदान करता है जो सिस्टम को अंतिम थ्रेड के लिए ऑब्जेक्ट को पंक्तिबद्ध नहीं करने की अनुमति देता है। एक ठीक से लिखा Dispose()/ अंतिम रूप से एक कॉल के साथ या उसके बिना ठीक से काम करना चाहिए GC.SupressFinalize()


2

उस विधि को उन Disposeवस्तुओं की विधि पर बुलाया जाना चाहिए जो IDisposableइस तरह से लागू होती हैं , इस तरह जीसी अंतिम रूप से किसी अन्य समय कॉल नहीं करेगा यदि कोई Disposeविधि को कॉल करता है।

देखें: GC.SuppressFinalize (ऑब्जेक्ट) विधि - Microsoft डॉक्स


9
मुझे लगता है कि "मस्ट" गलत है - "नहीं" भी - यह सिर्फ इतना है कि कुछ परिदृश्यों में, आप ऑब्जेक्ट को पंक्तिबद्ध / अंतिम रूप देने के ओवरहेड को समाप्त कर सकते हैं।
बेसिक

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

यदि ऑब्जेक्ट में अंतिम रूप है, तो .net ने अंतिम रूप से कतार में एक संदर्भ दिया।

चूंकि हमारे पास कॉल है Dispose(ture), यह स्पष्ट वस्तु है, इसलिए हमें इस काम को करने के लिए अंतिम रूप से कतार की आवश्यकता नहीं है।

तो GC.SuppressFinalize(this)अंतिम संदर्भ कतार में कॉल निकालें संदर्भ।


0

एक वर्ग, या कुछ भी से व्युत्पन्न, एक finalizer के साथ एक वस्तु के लिए पिछले लाइव संदर्भ पैदा हो सकती हैं, तो या तो GC.SuppressFinalize(this)या GC.KeepAlive(this)किसी भी आपरेशन कि प्रतिकूल कि finalizer से प्रभावित हो सकता के बाद वस्तु पर बुलाया जाना चाहिए, इस प्रकार यह सुनिश्चित करना कि finalizer जीता जब तक कि ऑपरेशन पूरा नहीं हो जाता, तब तक नहीं चलेंगे।

की लागत GC.KeepAlive()और GC.SuppressFinalize(this)अनिवार्य रूप से किसी भी वर्ग में एक ही है कि एक अंतिम रूप नहीं है, और वर्गों है कि अंतिम रूप से आम तौर पर फोन करना चाहिए GC.SuppressFinalize(this), तो बाद के समारोह के रूप में अंतिम चरण का Dispose()उपयोग करना हमेशा आवश्यक नहीं हो सकता है, लेकिन यह नहीं होगा गलत हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.