Hành vi thu gom rác cho người hủy diệt


9

Tôi có một lớp đơn giản được định nghĩa như dưới đây.

public class Person
{
    public Person()
    {

    }

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

    ~Person()
    {
        p = this;

    }
    public static Person p;
}

Trong phương thức chính

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

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

    }

Bộ thu gom rác có phải là tài liệu tham khảo chính cho Person.p không và khi nào chính xác thì hàm hủy sẽ được gọi?


Đầu tiên: một hàm hủy trong C # được coi là một bộ hoàn thiện . Thứ hai: đặt cá thể đơn lẻ của bạn thành cá thể đang được hoàn thiện có vẻ như là một ý tưởng rất tồi . Thứ ba: là Person1gì? Tôi chỉ nhìn thấy Person. Lần cuối: xem docs.microsoft.com/dotnet/csharp/programming-guide/iêu để biết cách thức hoạt động của công cụ hoàn thiện.
HimBromBeere

@HimBromBeere Person1thực sự Person, đã sửa lỗi chính tả.
Parimal Raj

@HimBromBeere Đây thực sự là một câu hỏi phỏng vấn, bây giờ theo sự hiểu biết của tôi, CG.Collect nên đã gọi hàm hủy nhưng nó đã không.
Parimal Raj

2
. (2) Thời điểm khi một bộ hoàn thiện được gọi là không thể dự đoán được.
Matthew Watson

@HimBromBeere và khi tôi đặt breakpoint tại Console.WriteLine Person.p sẽ xuất hiện dưới dạng null, bất kể GC.Collectcuộc gọi
Parimal Raj

Câu trả lời:


13

Điều bạn đang thiếu ở đây là trình biên dịch đang kéo dài tuổi thọ của bạn x biến cho đến khi kết thúc phương thức được định nghĩa - đó chỉ là thứ mà trình biên dịch thực hiện - nhưng nó chỉ thực hiện cho bản dựng DEBUG.

Nếu bạn thay đổi mã để biến được xác định trong một phương thức riêng biệt, nó sẽ hoạt động như bạn mong đợi.

Đầu ra của đoạn mã sau là:

False
True

Và mã:

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

Vì vậy, về cơ bản sự hiểu biết của bạn là chính xác, nhưng bạn không biết rằng trình biên dịch lén lút sẽ giữ cho biến của bạn tồn tại cho đến khi bạn gọiGC.Collect() - ngay cả khi bạn đặt nó thành null!

Như tôi đã lưu ý ở trên, điều này chỉ xảy ra đối với bản dựng DEBUG - có lẽ là do đó bạn có thể kiểm tra các giá trị cho các biến cục bộ trong khi gỡ lỗi đến cuối phương thức (nhưng đó chỉ là dự đoán!).

Mã ban đầu DOES hoạt động như mong đợi đối với bản dựng phát hành - do đó, đoạn mã sau xuất ra false, truecho bản dựng ĐÁNG TIN CẬY và false, falsecho bản dựng 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.
        }
    }
}

Là một phụ lục: Lưu ý rằng nếu bạn làm một cái gì đó trong bộ hoàn thiện cho một lớp làm cho một tham chiếu đến đối tượng được hoàn thành có thể truy cập được từ một gốc chương trình, thì đối tượng đó sẽ KHÔNG được thu gom rác trừ khi và cho đến khi đối tượng đó không còn tham khảo.

Nói cách khác, bạn có thể cho đối tượng "ở lại thực thi" thông qua bộ hoàn thiện. Điều này thường được coi là một thiết kế xấu, mặc dù!

Ví dụ, trong đoạn mã trên, nơi chúng tôi thực hiện _extendMyLifetime = thistrong trình hoàn thiện, chúng tôi đang tạo một tham chiếu mới cho đối tượng, vì vậy bây giờ nó sẽ không được thu gom rác cho đến khi _extendMyLifetime(và bất kỳ tham chiếu nào khác) không còn tham chiếu đến nó nữa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.