17

Почему приложение завершает свою работу? Ведь в деструкторе должно быть зацикливание:

namespace Core
{
    class Test
    {
        ~Test() { while (true); }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Test test = new Test();
        }
    }
}
Regent
  • 19,134

1 Answers1

16

Потому что в C# деструктор (а точнее, финализатор, так он называется) работает по-другому. Он вызывается не сразу, а когда-нибудь потом, да и то лишь при условии, что сборщик мусора удалит объект. Поскольку запуск сборщика мусора не гарантирован, то и вызов вашего финализатора тоже не гарантирован.

Кроме того, финализаторы бегут в отдельном потоке, а если в конце работы приложения финализация бежит слишком долго, то она насильно обрывается.

В вашем случае программа короткая и не нагружает память, понятно, что сборщик мусора запущен скорее всего не будет.


Для нужной вам семантики гарантированного вызова метода для уничтожения объекта вам нужно реализовать интерфейс IDisposable и воспользоваться конструкцией using.

class Test : IDisposable
{
    public void Dispose() { while (true) ; }
}

class Program
{
    static void Main(string[] args)
    {
        using (Test test = new Test())
        { }
    }
}

Дополнительная информация по теме:

VladD
  • 206,799
  • поток обрубается так и не вызвав деструктор. – Stanislav Petrov May 06 '17 at 07:12
  • @StanislavPetrov: Скорее всего просто до финализации и не доходит. – VladD May 06 '17 at 07:14
  • Ссылочку на What you know is wrong добавь ;) – Qwertiy May 06 '17 at 07:30
  • @StanislavPetrov, нет, думаю, в данном случае он вызывается, но через некоторое время прерывается. – Qwertiy May 06 '17 at 07:30
  • @Qwertiy: Угу, как раз был в процессе добавления :) – VladD May 06 '17 at 07:31
  • У меня на тестах на компе деструктор вызывается, но обрывается. Как раз из-за "если в конце работы приложения финализация бежит слишком долго, то она насильно обрывается". Думаю, именно этот кусок и есть истинно правильным ответом на сам вопрос, ведь GC при этом НЕ вызывается, что можно явно увидеть в окне Diagnostic tools по графику. (если добавить до и после Thread.Sleep(1000); ) – Andrew Stop_RU_war_in_UA May 06 '17 at 07:33
  • 1
    @Andrew https://ericlippert.com/2015/05/18/when-everything-you-know-is-wrong-part-one/ && https://ericlippert.com/2015/05/21/when-everything-you-know-is-wrong-part-two/ – Qwertiy May 06 '17 at 07:34
  • @Andrew: Объект помещается в очередь для финализации именно сборщиком мусора. Так что вам повезло, сборщик мусора увидел ваш объект. – VladD May 06 '17 at 07:36
  • @VladD, а почему мог не увидеть-то? Ну кроме превышения этого самого лимита? – Qwertiy May 06 '17 at 07:37
  • @Qwertiy: Например, рантайм мог решить вообще не запускать сборщик мусора, зачем, приложение-то завершается?. – VladD May 06 '17 at 07:41
  • @Andrew: Возможно, диагностическое окно показывает лишь полную сборку, а не Gen0. – VladD May 06 '17 at 07:46
  • @VladD, а вдруг там глобальные для системы семафоры? Как-то без причины финализаторы пропускать было бы сранно. Хотя FailFast тоже никто не отменял :) – Qwertiy May 06 '17 at 07:53
  • @Qwertiy: Ну, гарантии финализации нет, так что надеяться на это для очистки глобальных объектов тоже не стоит. – VladD May 06 '17 at 07:59
  • 1
    @Qwertiy для таких случаев есть CriticalFinalizerObject – Pavel Mayorov May 06 '17 at 08:00