फाइनल के बाद GC.Collect () [डुप्लिकेट] को नहीं बुलाया गया

Aug 17 2020

मुझे लगता है कि मुझे कुछ मौलिक याद आ रही है और आशा है कि आप मदद कर सकते हैं। नीचे कोड एक ऑब्जेक्ट बनाता है, संदर्भ को हटाता है और कचरा कलेक्टर को कॉल करता है। मेरी उम्मीद यह थी कि रीडलाइन में खड़े होने पर SomeClass के फाइनलिस्ट को बुलाया जाएगा। यह नहीं है मैंने GC.Collect को एक लूप में कॉल करने की कोशिश की है, कुछ नींद () कॉल को फाइनल करने के लिए थ्रेड शुरू किया है। ऐसा नही होता है।

केवल जब फाइनल समाप्त होता है तो हिट होता है, लेकिन आश्चर्यजनक रूप से यह दो बार हिट होता है। मैं क्या खो रहा हूँ?

class Program
{
    public static void Main(string[] args)
    {
        SomeClass some = new SomeClass("Hello World!");
        some = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine("Done");
        Console.ReadLine();
    }
}

class SomeClass 
{
    string ss;
    public SomeClass(string s) { ss = s; }
    ~SomeClass()
    {
        var hash = this.GetHashCode();
    }
}

परिशिष्ट डिबग मोड बनाम रिलीज़ मोड में एक प्रोग्राम चलाने में अंतर है। नीचे प्रोग्राम डिबग मोड में उत्पादन करता है Start - Done - Finalizeजबकि रिलीज मोड में लॉगफाइल शो होता है Start - Finalize - Done। बाद में वही हुआ जिसकी मुझे उम्मीद थी।

class Program
{
    private static string logfile = @"c:\temp\log.txt";
    public static void Main(string[] args)
    {
        File.WriteAllText(logfile, "Start\n");
        SomeClass some = new SomeClass("Hello World!");
        some = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        File.AppendAllText(logfile, "Done\n");
    }
}

class SomeClass 
{
    private static string logfile = @"c:\temp\log.txt";
    public string SomeString { get; set; }
    public SomeClass(string s) { SomeString = s; }
    ~SomeClass()
    {
        File.AppendAllText(logfile, "Finalize\n");
    }
}

जवाब

1 V0ldek Aug 16 2020 at 23:33

एकत्र की गई वस्तुएँ अंतिम रूप देने के लिए उपयुक्त हो जाती हैं और उन्हें अंतिम रूप देने वाली कतार में डाल दिया जाता है। इस बात की कोई गारंटी नहीं है कि वे अंतिम रूप से चलने वाले हैं

मैं आपको इस पर एरिक लिपर्ट के महान पदों पर पुनर्निर्देशित करने जा रहा हूं, उचित रूप से "जब आप जानते हैं कि सब कुछ गलत है।" विशेष रूप से:

मिथक: एक चर को शून्य में सेट करने से अंतिम वस्तु उस चर पर चलने का कारण बनती है जिसे पहले चर द्वारा संदर्भित किया गया था। चर को शून्य में सेट करने से चर का मान बदलने के अलावा तुरंत कुछ भी नहीं होता है। यदि चर विचाराधीन वस्तु का अंतिम जीवित संदर्भ था, तो उस तथ्य की खोज की जाएगी जब कचरा कलेक्टर वस्तु में जो भी पीढ़ी के लिए कलेक्टर को चलाता है। (यदि यह बिल्कुल भी चलता है, जो यह नहीं हो सकता है। कोई गारंटी नहीं है। कि जीसी चलता है।)

और यहां तक ​​कि GC.Collect():

मिथक: कॉलिंग के GC.Collect()कारण अंतिम रूप से चलने वाले होते हैं। नहीं, यह एक संग्रह का कारण बनता है। यह उन वस्तुओं की पहचान कर सकता है जो अंतिम रूप देने के लिए उम्मीदवार हैं, लेकिन यह अंतिम धागा को अनुसूचित होने के लिए मजबूर नहीं करता है। यदि वह है जो आप चाहते हैं - परीक्षण प्रयोजनों के लिए कृपया! - तो बुलाओ GC.WaitForPendingFinalizers()

इसलिए सफलता का सबसे अच्छा मौका है GC.WaitForPendingFinalizers()। लेकिन फिर भी, आपको शेष पोस्ट ( और इसके सीक्वल ) का उल्लेख करते हुए , फ़ाइनलीज़र्स रुन के लिए निर्देशित नहीं हैं । उस पर निर्भर न रहें।

मैंने इस प्रश्न पर अधिक विस्तृत विवरण लिखा है ताकि आप इसे आगे के शोध के लिए शुरुआती बिंदु के रूप में उपयोग कर सकें।