विध्वंसक के लिए कचरा संग्राहक व्यवहार


9

मेरे पास एक साधारण वर्ग है जिसे नीचे परिभाषित किया गया है।

public class Person
{
    public Person()
    {

    }

    public override string ToString()
    {
        return "I Still Exist!";
    }

    ~Person()
    {
        p = this;

    }
    public static Person p;
}

मुख्य विधि में

    public static void Main(string[] args)
    {
        var x = new Person();
        x = null;

        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine(Person.p == null);

    }

क्या कूड़ा उठाने वाले को पर्सन के लिए मुख्य संदर्भ माना जाता है। पीपी को कब विध्वंसक कहा जाएगा?


पहला: C # में एक विध्वंसक अंतिम रूप देने वाला है । दूसरा: उदाहरण के लिए अपने सिंगलटन-इंस्टेंस को अंतिम रूप दिया जाना एक बहुत ही बुरे विचार की तरह लगता है । तीसरा: क्या है Person1? मैं ही देखता हूं Person। अंतिम: कैसे अंतिम रूप देने के लिए docs.microsoft.com/dotnet/csharp/programming-guide/… देखें ।
हिमब्रोबेरे

@HimBromBeere Person1वास्तव में Person, टाइपो तय किया है।
परिमल राज

@HimBromBeere यह वास्तव में एक साक्षात्कार का प्रश्न था, अब मेरी समझ के अनुसार, CG.Collect को विध्वंसक का आविष्कार करना चाहिए था, लेकिन यह नहीं हुआ।
परिमल राज

2
(१) यदि आप वस्तु को पुन: संदर्भित कर रहे हैं, तो यह फ़ाइनलीज़र है, तो यह तब तक एकत्र नहीं होगा जब तक कि संदर्भ अब एक रूट से उपलब्ध नहीं है (इसलिए इसमें इसके कचरा संग्रहण में देरी का प्रभाव है)। (२) उस समय की बात जब किसी फाइनलर को बुलाया जाता है, वह अनुमान नहीं है।
मैथ्यू वाटसन

@HimBromBeere और जब मैं Console.WriteLine Person.p पर ब्रेकपॉइंट लगाता हूं, तो GC.Collectकॉल की परवाह किए बिना, अशक्त के रूप में आ रहा है
परिमल राज

जवाबों:


13

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

यदि आप कोड को बदलते हैं ताकि चर एक अलग विधि में परिभाषित हो, तो यह आपकी अपेक्षा के अनुरूप काम करेगा।

निम्नलिखित कोड का आउटपुट है:

False
True

और कोड:

using System;

namespace ConsoleApp1
{
    class Finalizable
    {
        ~Finalizable()
        {
            _extendMyLifetime = this;
        }

        public static bool LifetimeExtended => _extendMyLifetime != null;

        static Finalizable _extendMyLifetime;
    }

    class Program
    {
        public static void Main()
        {
            test();

            Console.WriteLine(Finalizable.LifetimeExtended); // False.

            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine(Finalizable.LifetimeExtended); // True.
        }

        static void test()
        {
            new Finalizable();
        }
    }
}

तो मूल रूप से आपकी समझ सही थी, लेकिन आप नहीं जानते थे कि डरपोक कंपाइलर आपके चर को जीवित रखने वाला था जब तक कि आपको फोन नहीं किया जाता GC.Collect()- भले ही आपने इसे स्पष्ट रूप से शून्य करने के लिए सेट किया हो!

जैसा कि मैंने ऊपर उल्लेख किया है, यह केवल डेबग बिल्ड के लिए होता है - संभवतः इसलिए आप विधि के अंत में डिबगिंग करते समय स्थानीय चर के लिए मानों का निरीक्षण कर सकते हैं (लेकिन यह सिर्फ एक अनुमान है!)।

मूल कोड एक रिलीज बिल्ड के लिए अपेक्षित के रूप में काम करता है - इसलिए निम्नलिखित कोड false, trueएक निर्माण के लिए और false, falseएक DEBUG के लिए आउटपुट :

using System;

namespace ConsoleApp1
{
    class Finalizable
    {
        ~Finalizable()
        {
            _extendMyLifetime = this;
        }

        public static bool LifetimeExtended => _extendMyLifetime != null;

        static Finalizable _extendMyLifetime;
    }

    class Program
    {
        public static void Main()
        {
            new Finalizable();

            Console.WriteLine(Finalizable.LifetimeExtended); // False.

            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine(Finalizable.LifetimeExtended); // True iff RELEASE build.
        }
    }
}

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

दूसरे शब्दों में, आप किसी फ़ाइनलीज़र के माध्यम से किसी वस्तु को "निष्पादन पर रोक" दे सकते हैं। यह आमतौर पर एक बुरा डिज़ाइन माना जाता है, हालाँकि!

उदाहरण के लिए, ऊपर दिए गए कोड में, जहां हम _extendMyLifetime = thisफाइनल में करते हैं, हम ऑब्जेक्ट के लिए एक नया संदर्भ बना रहे हैं, इसलिए यह अब कचरा एकत्र नहीं किया जाएगा _extendMyLifetime(और किसी भी अन्य संदर्भ) अब इसे संदर्भित नहीं करता है।

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