Yıkıcı için Çöp Toplayıcı Davranışı


9

Aşağıda tanımlanan basit bir sınıf var.

public class Person
{
    public Person()
    {

    }

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

    ~Person()
    {
        p = this;

    }
    public static Person p;
}

Ana yöntemde

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

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

    }

Çöp toplayıcının Person.p için ana referansı olması gerekir mi ve yıkıcı tam olarak ne zaman çağrılır?


Birincisi: C # 'daki bir yıkıcı sonlandırıcıdır . İkincisi: singleton örneğinizi sonlandırılan örneğe ayarlamak çok kötü bir fikir gibi görünüyor . Üçüncüsü: Person1Nedir? Sadece görüyorum Person. Sonuncu: sonlandırıcıların nasıl çalıştığı hakkında docs.microsoft.com/dotnet/csharp/programming-guide/… adresine bakın .
HimBromBeere

@HimBromBeere Person1aslında Person, yazım hatası düzeltildi.
Parimal Raj

@HimBromBeere Bu aslında bir röportaj sorusuydu, şimdi anladığım kadarıyla CG.Collect yıkıcıyı çağırmış olmalı ama olmadı.
Parimal Raj

2
(1) Sonlandırılmakta olan nesneye finializer içinde yeniden başvurursanız, bu referans artık bir kökten erişilinceye kadar GARBAGE TOPLANMAYACAKTIR (bu nedenle, çöp toplama işlemini geciktirme etkisi vardır). (2) Bir sonlandırıcının çağrıldığı zaman öngörülebilir değildir.
Matthew Watson

@HimBromBeere ve ben Console.WriteLine Person.p kesme noktası koymak zaman GC.Collectçağrı ne olursa olsun, boş olarak geliyor
Parimal Raj

Yanıtlar:


13

Burada eksik xolan şey, derleyicinin tanımlandığı yöntemin sonuna kadar değişkeninizin ömrünü uzatmasıdır - bu sadece derleyicinin yaptığı bir şeydir - ancak bunu sadece bir DEBUG derlemesi için yapar.

Kodu, değişkeni ayrı bir yöntemde tanımlanacak şekilde değiştirirseniz, beklediğiniz gibi çalışır.

Aşağıdaki kodun çıktısı:

False
True

Ve kod:

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

Yani temelde anlayış doğru, ama sen kadar sinsi derleyici sizin değişken canlı tutmak için gittiğini bilmiyordu sonra aradığınız GC.Collect()- Açıkça boş olarak ayarlayın bile!

Yukarıda belirttiğim gibi, bu sadece bir DEBUG derlemesi için olur - muhtemelen yöntemin sonuna kadar hata ayıklarken yerel değişkenlerin değerlerini inceleyebilirsiniz (ancak bu sadece bir tahmin!).

Özgün kod, bir sürüm derlemesi için beklendiği gibi çalışır - bu nedenle, aşağıdaki kod false, trueRELEASE derlemesi ve false, falseDEBUG derlemesi için çıkar:

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.
        }
    }
}

Ek olarak: Sonlandırılmakta olan nesneye yapılan başvurunun bir program kökünden erişilebilmesine neden olan bir sınıf için sonlandırıcıda bir şey yaparsanız, o nesne artık olmadıkça ve yapılmadıkça o nesnenin çöp toplanmayacağını unutmayın. başvurulan.

Başka bir deyişle, bir nesneye sonlandırıcı aracılığıyla "yürütmenin durdurulması" verebilirsiniz. Bu genellikle kötü bir tasarım olarak kabul edilir!

Örneğin _extendMyLifetime = this, sonlandırıcıda yaptığımız yukarıdaki kodda , nesneye yeni bir referans oluşturuyoruz, bu yüzden artık _extendMyLifetime(ve başka bir referans) artık referans verene kadar çöp toplanmayacak .

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.