Почему сборщик мусора не запускает финализатор?

У меня есть эта небольшая программа (настоящая программа, конечно, сильно отличается).

using System;

namespace Finalizer
{
    public class Simple
    {
        public Simple()
        {
            Console.WriteLine("Constructor");
        }
        ~Simple()
        {
            Console.WriteLine("Finalizer");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            var s = new Simple();
            s = null;
            GC.Collect();
            Console.WriteLine("Collected");
            Console.ReadKey();
        }
    }
}

И это вывод:

Hello World!
Constructor
Collected

Я не понимаю, почему я не вижу строку Finalizer.

Кто угодно?


person Peter Poulsen    schedule 14.02.2021    source источник
comment
GC недетерминирован. Если ваше приложение не запрашивает больше памяти, скорее всего, сборщик мусора обдумывает ваш ход. Он имеет несколько встроенных эвристик, но основные из них основаны на спросе.   -  person Marc Gravell    schedule 14.02.2021
comment
Также обратите внимание, что s, вероятно, все еще находится в стеке. попробуй void local() { var s = new Simple(); } local();   -  person TheGeneral    schedule 14.02.2021
comment
Какую версию фреймворка вы используете? Я вижу Finalizer в выводе, когда пробую его.   -  person Matthew Watson    schedule 14.02.2021
comment
Вы запускаете сборку отладки или выпуска?   -  person mjwills    schedule 14.02.2021
comment
Я хотел бы сделать небольшое замечание, а именно то, что в реальных приложениях потребность в финализаторах невероятно редка (я никогда не писал их почти за 20 лет разработки C#). Как вы думаете, зачем он вам нужен?   -  person mjwills    schedule 14.02.2021
comment
Примечания: (1) Финализатор вызывается для сборки .Net Framework. (2) Если вы поместите создание Simple в отдельный метод, который вы вызываете из Main(), финализатор будет вызываться для .Net Framework и .Net Core.   -  person Matthew Watson    schedule 14.02.2021
comment
@MatthewWatson Даже если это правда сегодня, это не обещано.   -  person mjwills    schedule 14.02.2021
comment
В .Net Core, если вы хотите быть уверены, что финализатор объекта вызывается до закрытия приложения, объявите его как Filed (private static Simple simple = new Simple();). Когда вы устанавливаете его в null и вызываете GC.Collect(), финализатор запускается немедленно. В .Net Framework это все равно называется.   -  person Jimi    schedule 14.02.2021
comment
@ Джими Это не обещано. Он может это сделать, а может и нет (поскольку он не обязан это делать по контракту).   -  person mjwills    schedule 14.02.2021
comment
@ 00110001 — Сборщик мусора может собирать объекты после их последней ссылки в методе. Неважно, находится он в стеке или нет.   -  person Enigmativity    schedule 14.02.2021
comment
@mjwills Это правда, что нет гарантии, что Finalizer будет вызываться каждый раз, когда вы считаете, что это должно быть сделано, но в контексте этого вопроса вызывается деструктор статического объекта.   -  person Jimi    schedule 14.02.2021
comment
Попробуйте GC.Collect(2); GC.WaitForPendingFinalizers(); GC.Collect(2); из вне функции, которая создает и удаляет объект. И попробуй в релизной сборке.   -  person Charlieface    schedule 14.02.2021
comment
@mjwills Действительно, это, конечно, не обещано для .Net Core (и не гарантируется для .Net Framework), но я просто хотел обратить внимание на разницу в поведении между .Net Framework и .Net Core. Эта разница на самом деле задокументирована здесь: In .NET Framework applications (but not in .NET Core applications), finalizers are also called when the program exits.   -  person Matthew Watson    schedule 14.02.2021
comment
@mjwills CriticalFinalizerObject   -  person Jimi    schedule 16.02.2021
comment
@Jimi Обычные разработчики не должны писать финализаторы. Они определенно не должны наследоваться от этого класса. ;)   -  person mjwills    schedule 17.02.2021
comment
@mjwills Кто такой нормальный разработчик? Вы имеете в виду, что ребята из команды .Net ненормальны? :) Этот класс (и другие) являются частью Framework. Вероятно, вы имеете в виду, что не следует писать финализаторы при использовании объектов .Net (здесь нет необходимости в деструкторе). Иногда приходится писать финализаторы. Это не совсем исключительная задача. Вероятно, гораздо реже в управляемой среде, но все же требуется в определенных условиях. -- Но, как и в этом случае, финализаторы могут быть гарантированно запущены. Например, когда у вас есть статический объект Field, и вы хотите, чтобы ваш финализатор выполнялся в конкретном случае (запланировано).   -  person Jimi    schedule 17.02.2021
comment
@Jimi Я думаю, будет справедливо предположить, что я исключаю разработчиков самой структуры самой, поскольку я уверен, что вы полностью осведомлены. You have to write finalizers sometimes. Иногда да. Но очень редко. joeduffyblog.com/2005/12 /27/ Но вы это знаете - вы спорите ради спора. ;)   -  person mjwills    schedule 17.02.2021
comment
@mjwills Не спорить, на самом деле, просто тыкать вас (и/или ОП, они могут быть заинтересованы). Одни мнения более интересны, чем другие. Кстати, я знаю об этой статье, я также знаю, что Стивен Тауб говорит о финализаторах; например: Действительно следует обновить правила удаления, чтобы указать разработчикам правильное направление. Это интересное обсуждение еще и потому, что оно затронуло документы MSDN, которые теперь отражают выводы из этих аргументов. Я согласен с тем, что критические финализаторы — это другая порода.   -  person Jimi    schedule 17.02.2021