2009-04-27 26 views
6

अभ्यास में मेरा अवलोकन यह रहा है कि GC.SuppressFinalize हमेशा कॉलर को अंतिम बार दबाएगा। यह हो सकता है कि फाइनलर को फिर भी बुलाया जाए। मुझे आश्चर्य है कि GC.SuppressFinalize में की प्रकृति गारंटी से सिस्टम द्वारा की प्रकृति है?क्या GC.SuppressFinalize गारंटी है?


अधिक जानकारी

के बाद जानकारी quesiton के लिए और अधिक संदर्भ प्रदान अगर जरूरत मदद मिल सकती है।

अनुरोध है कि सिस्टम निर्दिष्ट ऑब्जेक्ट के लिए finalizer फोन नहीं:

GC.SuppressFinalize दस्तावेज़ सारांश राज्य है कि एक अनुरोध है नहीं करता है।

मुझे आश्चर्य है कि यह शब्द का आकस्मिक उपयोग था या वास्तव में रन-टाइम व्यवहार का वर्णन करने का इरादा था।

मैं निम्नलिखित SingletonScope वर्ग Schnell परियोजना है, जो एक original idea by Ian Griffiths पर आधारित था सिवाय इसके कि इसे अधिक सामान्यकृत है से लिया के साथ इस देखा है। विचार है कि डिबग बिल्ड में, Dispose विधि को कॉल किया गया था या नहीं। यदि नहीं, तो फाइनल में अंततः लात मार जाएगा और कोई चेतावनी दे सकता है। यदि Dispose को GC.SuppressFinalizeकहा जाता है तो फाइनर को फायरिंग से रोकें। दुर्भाग्य से, चेतावनियां किसी भी तरह से आग लगती हैं, लेकिन एक निश्चित फैशन में नहीं। यही है, वे प्रत्येक दौड़ पर आग नहीं डालते हैं।

#region License, Terms and Author(s) 
// 
// Schnell - Wiki widgets 
// Copyright (c) 2007 Atif Aziz. All rights reserved. 
// 
// Author(s): 
//  Atif Aziz, http://www.raboof.com 
// 
// This library is free software; you can redistribute it and/or modify it 
// under the terms of the GNU Lesser General Public License as published by 
// the Free Software Foundation; either version 2.1 of the License, or (at 
// your option) any later version. 
// 
// This library is distributed in the hope that it will be useful, but WITHOUT 
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
// License for more details. 
// 
// You should have received a copy of the GNU Lesser General Public License 
// along with this library; if not, write to the Free Software Foundation, 
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
// 
#endregion 

namespace WikiPad 
{ 
    #region Imports 

    using System; 
    using System.Diagnostics; 

    #endregion 

    // 
    // NOTE: To use SingletonScope and ISingletonScopeHelper with value 
    // types, use Nullable<T>. For example, if the type of value to scope 
    // is ThreadPriority then use ISingletonScopeHelper<ThreadPriority?> 
    // and SingletonScope<ThreadPriority?>. 
    // 

    // 
    // In debug builds, this type is defined as a class so a finalizer 
    // can be used to detect an undisposed scope. 
    // 

    /// <summary> 
    /// Designed to change a singleton and scope that change. After exiting 
    /// the scope, the singleton is restored to its value prior to entering 
    /// the scope. 
    /// </summary> 

    #if !DEBUG 
    internal struct SingletonScope<T, H> 
    #else 
    internal sealed class SingletonScope<T, H> 
    #endif 
     : IDisposable 
     where H : ISingletonScopeHelper<T>, new() 
    { 
     private T _old; 

     public SingletonScope(T temp) 
     { 
      _old = Helper.Install(temp); 
     } 

     private static H Helper 
     { 
      get { return new H(); } 
     } 

     public void Dispose() 
     { 
      // 
      // First, transfer fields to stack then nuke the fields. 
      // 

      var old = _old; 
      _old = default(T); 

      // 
      // Shazam! Restore the old value. 
      // 

      Helper.Restore(old); 

      #if DEBUG 
      GC.SuppressFinalize(this); // Only when defined as a class! 
      #endif 
     } 

     #if DEBUG 

     // 
     // This finalizer is used to detect an undisposed scope. This will 
     // only indicate that the scope was not disposed but (unfortunately) 
     // not which one and where since GC will probably collect much later 
     // than it should have been disposed. 
     // 

     ~SingletonScope() 
     { 
      Debug.Fail("Scope for " + typeof(T).FullName + " not disposed!"); 
     } 

     #endif 
    } 
} 

एक पूर्ण काम कर उदाहरण संकलन के निर्देश के साथ http://gist.github.com/102424 पर उपलब्ध है, लेकिन ध्यान दें है कि समस्या को निर्धारणात्मक अब तक reproduced नहीं किया जा सकता।

+0

निपटान विधि में ट्रेस नहीं है, मुझे लगता है कि आप सुनिश्चित हैं कि इसे अंतिम रूप से पहले सफलतापूर्वक बुलाया जाता है? – Groo

+0

@ ग्रूओ: हाँ मुझे यकीन है कि जब तक सी # में टूटा हुआ नहीं है। :) –

उत्तर

0

मैंने कई बार सटीक पैटर्न का उपयोग किया है और जीसी। सुपर्रेसफिनलाइज हमेशा काम पर दिखाई देता है।

ध्यान रखें कि जीसी.रेरेजिस्टर फोरफिनलाइज के लिए कॉल ऑब्जेक्ट को अंतिम रूप देने के लिए फिर से पंजीकृत करने का कारण बन जाएगा।

जब भी मैं ऊपर की तकनीक का उपयोग करता हूं, मैं हमेशा यह सुनिश्चित करता हूं कि ऑब्जेक्ट निर्माण के दौरान एक पूर्ण स्टैक ट्रेस शामिल करें ताकि मैं गैर-डिस्पोजेड ऑब्जेक्ट आवंटित विधि को ट्रैक कर सकूं।

ईजी। कन्स्ट्रक्टर में

StackFrame frame = new StackFrame(1); 

और फाइनलजर के दौरान आपके डीबग संदेश में रिपोर्ट करें।

इसके अलावा, मैं आपका जीसी देखता हूं। अप्रेसफिनलाइज अंततः खंड में नहीं है, अगर निपटान के दौरान एक अपवाद फेंक दिया जाता है, तो आपके ऑब्जेक्ट फ़ाइनलाइज़र को दबाया नहीं जाएगा।

+0

जैसा कि आप देख सकते हैं, GC.ReRegisterForFinalize के साथ कोड में कोई कॉल नहीं है। –

+0

मुझे पता है कि यह सुनिश्चित करने का प्रयास कर रहा था कि उत्तर पूरा हो गया है, क्या आपने स्टैकफ्रेम डीबगिंग चाल का प्रयास किया था? –

+0

@ sambo99 मैं उस चाल को जोड़ने पर विचार करूंगा। इस बीच, यह इस मामले में मदद नहीं करेगा क्योंकि मुझे यकीन है कि निपटान को बुलाया गया था क्योंकि स्कोप ऑब्जेक्ट का उपयोग सी # से उपयोग के साथ किया जाता है। मैं सोच रहा था कि क्या मुझे अंतिम रूप में अधिक रक्षात्मक होने की आवश्यकता है। –

4

एक विषमता आप देख रहे हैं कि अंतिम उदाहरण अभी भी चल रहा है, जबकि एक इंस्टेंस विधि अभी भी चल रही है, तब तक जब तक कि इंस्टेंस विधि बाद में किसी भी चर का उपयोग नहीं करती है।तो आपके नमूना कोड में, Dispose विधि पहली पंक्ति के बाद किसी भी आवृत्ति चर का उपयोग नहीं करती है। उदाहरण को अंतिम रूप दिया जा सकता है, भले ही Dispose अभी भी चल रहा है।

आप Dispose विधि के अंत में GC.KeepAlive(this) के लिए एक कॉल सम्मिलित हैं, तो आप मिल सकता है समस्या दूर चला जाता है।

क्रिस Brumme इस बारे में एक blog post है, और मुझे लगता है कि वहाँ एक और कहीं आस-पास ...

+0

जॉन, मैं उस चेतावनी के बारे में अच्छी तरह से जानता हूं, लेकिन फाइनलाइज़र और डीबग। आवेदन में मौजूद होने पर इसमें विफल कोड प्रतीत होता है, जो मुझे लगता है कि लंबित अंतिमकर्ता निष्पादित किए जा रहे हैं। GC.SuppressFinalize के बाद यह * लंबा * होता है। –

+0

@ जो कुछ नमूना कोड टूटता है जो निपटता है प्रबुद्ध होगा, मुझे आश्चर्य है कि एक नमूना को गठबंधन किया जा सकता है। –

+0

@ sambo99: मेरे पास अभी नमूना लिखने का समय नहीं है, लेकिन मैं इसे बाद में करने की कोशिश करूंगा। असल में यदि आप जीसी को कॉल करते हैं। कोलेक्ट()/जीसी। वैटफोरपेन्डिंग फाइनलाइजर्स, आप इसे समाप्त होने से पहले इंस्टेंस को अंतिम रूप दे सकते हैं। –

3

मैं हमेशा IDisposable इंटरफ़ेस को लागू करने के लिए इस डिजाइन पद्धति का उपयोग कर रहा हूँ। (जो माइक्रोसॉफ्ट द्वारा सुझाया गया है) और मेरे लिए जीसी। सप्रेसप्रेस हमेशा एक गारंटी की प्रकृति है!

using System; 
using System.ComponentModel; 

//The following example demonstrates how to use the GC.SuppressFinalize method in a resource class to prevent the clean-up code for the object from being called twice. 

public class DisposeExample 
{ 
    // A class that implements IDisposable. 
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources. 
    public class MyResource : IDisposable 
    { 
     // Pointer to an external unmanaged resource. 
     private IntPtr handle; 
     // Other managed resource this class uses. 
     private readonly Component component = new Component(); 
     // Track whether Dispose has been called. 
     private bool disposed; 

     // The class constructor. 
     public MyResource(IntPtr handle) 
     { 
      this.handle = handle; 
     } 

     // Implement IDisposable. 
     // Do not make this method virtual. 
     // A derived class should not be able to override this method. 
     public void Dispose() 
     { 
      Dispose(true); 
      // This object will be cleaned up by the Dispose method. 
      // Therefore, you should call GC.SupressFinalize to 
      // take this object off the finalization queue 
      // and prevent finalization code for this object 
      // from executing a second time. 
      GC.SuppressFinalize(this); 
     } 

     // Dispose(bool disposing) executes in two distinct scenarios. 
     // If disposing equals true, the method has been called directly 
     // or indirectly by a user's code. Managed and unmanaged resources 
     // can be disposed. 
     // If disposing equals false, the method has been called by the 
     // runtime from inside the finalizer and you should not reference 
     // other objects. Only unmanaged resources can be disposed. 
     private void Dispose(bool disposing) 
     { 
      // Check to see if Dispose has already been called. 
      if (!disposed) 
      { 
       // If disposing equals true, dispose all managed 
       // and unmanaged resources. 
       if (disposing) 
       { 
        // Dispose managed resources. 
        component.Dispose(); 
       } 

       // Call the appropriate methods to clean up 
       // unmanaged resources here. 
       // If disposing is false, 
       // only the following code is executed. 
       CloseHandle(handle); 
       handle = IntPtr.Zero; 
      } 
      disposed = true; 
     } 

     // Use interop to call the method necessary 
     // to clean up the unmanaged resource. 
     [System.Runtime.InteropServices.DllImport("Kernel32")] 
     private extern static Boolean CloseHandle(IntPtr handle); 

     // Use C# destructor syntax for finalization code. 
     // This destructor will run only if the Dispose method 
     // does not get called. 
     // It gives your base class the opportunity to finalize. 
     // Do not provide destructors in types derived from this class. 
     ~MyResource() 
     { 
      // Do not re-create Dispose clean-up code here. 
      // Calling Dispose(false) is optimal in terms of 
      // readability and maintainability. 
      Dispose(false); 
     } 
    } 

    public static void Main() 
    { 
     // Insert code here to create 
     // and use a MyResource object. 
    } 
} 

स्रोत: MSDN: GC.SuppressFinalize Method

+0

बिंगो! आपका कार्यान्वयन इस बात पर परवाह नहीं करता है कि अंतिमकर्ता को दमनकारी दमन के रूप में बुलाया जाता है या नहीं, क्योंकि इसे रक्षात्मक रूप से कोड किया जाता है। आपका फाइनलाइज़र वापस निपटान में कॉल करता है और इसका निपटारा करने के लिए एक अतिरिक्त ध्वज है यदि इसे निपटाया गया है या नहीं। मैंने डीबग को नग्न कॉल किया। मेरे फाइनल में यह मानते हुए कि अगर मैं जीसी सपप्रेसफिनलाइज का उपयोग करता हूं, तो रनटाइम की गारंटी के बारे में मेरा सवाल है। –

+2

यदि आप मेरा कोड चलाते हैं, तो आप देखेंगे कि विनाशक (फ़ाइनलाइज़र) तभी चलाएगा जब निपटान विधि को कॉल नहीं किया जाता है। – CSharper

+0

क्या कोई कारण है कि कोड एक ही हैंडल पर दो बार क्लोजहैंडल को कॉल नहीं कर सका अगर किसी ऑब्जेक्ट को अंतिम रूप देने के लिए कतारबद्ध किया जाता है, जबकि पुनरुत्थान-ट्रैकिंग WeakReference मौजूद है, और यह कि WeakReference को एक मजबूत संदर्भ में परिवर्तित कर दिया गया है जो कि हो जाता है। बस सही समय? मैं इससे बचने के लिए निपटान झंडे से निपटने के दौरान IInterlocked.Exchange या Interlocked.CompareExchange का उपयोग करने के इच्छुक हूं। – supercat

0

जब एक उपयोगकर्ता परिभाषित finalizer के साथ एक वस्तु का निर्माण किया है, क्रम में यह करने के लिए एक आंतरिक संदर्भ रखने के लिए इसलिए जब यह उपयोगकर्ता कोड में पहुँच योग्य नहीं हो जाता है यह अभी भी है हो सकता है रनटाइम के अंतिमकरण धागे में बुलाया फाइनलाइज़र। अंतिम समय पर कॉल करते समय उस समय सार का सार माना जाता है, यदि उपयोगकर्ता ने उनसे दबाने का अनुरोध किया है तो वस्तुओं को कतार में रखने का कोई मतलब नहीं है। मेरे परीक्षण सीएलआई कार्यान्वयन में, मैं उन ऑब्जेक्ट्स के शीर्षलेख में एक SuppressFinalizer ध्वज रखता हूं जिसमें उपयोगकर्ता द्वारा परिभाषित अंतिमकर्ता होते हैं। अगर ध्वज सत्य है तो अंतिम वस्तु धागा उस वस्तु को कतार में पहुंचता है, तो अंतिमकर्ता कॉल छोड़ दिया जाता है। मैं कतार से ऑब्जेक्ट को नहीं हटाता, इसलिए मैं ओ (एन) के बजाय GC.SuppressFinalize() ओ (1) पर कॉल रख सकता हूं, जहां एन आवंटित अंतिम करने योग्य ऑब्जेक्ट्स की संख्या है (मैं इस नीति को एक में बदल सकता हूं बाद में स्थगित हटाने नीति)।

1

मैंने फाइनल में एक अमान्य ऑपरेशन अपवाद फेंक दिया जो कि उन प्रकारों को ढूंढना आसान बनाता है जिन्हें ठीक से निपटान नहीं किया गया है। जब निपटान() को कहा जाता है जहां जीसी। सुपरप्रेसफिनलाइज का आह्वान किया जाता है, तो मुझे कभी अपवाद नहीं मिलता है।

संबंधित मुद्दे