Всегда ли выполняются финализаторы .net?

Гарантировано ли выполнение финализаторов в .NET в какой-то момент (перебои в подаче электроэнергии и т.п.)? Я знаю, как работает сборщик мусора, и что не детерминировано, когда именно они будут работать.

(Поиск не дал хороших ответов, поэтому я добавляю этот вопрос в ожидании слияния с не очень легкими для обнаружения фактическими ответами. Кроме того, я уже знаю ответ и собираюсь добавить его через несколько дней, если никто об этом не упомянул.)


person mafu    schedule 11.08.2010    source источник


Ответы (2)


На самом деле финализаторы могут быть никогда не запускаться, как объясняет Рэймонд Чен . Довольно забавно, что этот вопрос задают во время его ежегодной недели CLR, всего через два дня после того, как он это объяснил :)

Для ленивых вывод (а точнее, один):

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

Если вам интересно, можно ли полагаться на финализаторы, это уже все, что вам нужно знать: не полагайтесь на финализаторы.

Как заявляет Раймонд Чен в связанной статье:

Финализаторы - это подстраховка, а не основное средство восстановления ресурсов.

Если вы ищете, как освободить ресурсы, взгляните на шаблон Disposable.


Финализатор может не работать, например, если:

  • Другой финализатор выдает исключение.
  • Другой финализатор занимает более 2 секунд.
  • Все финализаторы вместе занимают более 40 секунд.
  • Домен приложения выдает сбой или выгружается (хотя вы можете обойти это с помощью критического финализатора (CriticalFinalizerObject, SafeHandle или что-то в этом роде)
  • Сборка мусора не происходит
  • Процесс вылетает

(Примечание: значения времени могли со временем измениться, но определенно было верно некоторое время назад.)

Думаю, есть еще много вещей, из-за которых финализаторы никогда не запускаются. Суть в том, что помимо цитаты г-на Чена, финализаторы - это страховочная сетка, уменьшающая влияние ошибок, потому что, например, ресурсы высвобождаются когда-нибудь, что лучше, чем никогда, если вы забудете сделать это явно.

person OregonGhost    schedule 11.08.2010
comment
Не могли бы вы процитировать еще важные части? И да, возможно, спрашивающий с нетерпением ждал именно этой ссылки. ;) - person mafu; 11.08.2010
comment
На самом деле, поскольку многие люди спрашивают, как они могут полагаться на поведение финализатора, я думаю, что я сделал процитировал самую важную часть;) С другой стороны, другие блоки в статье также могут быть интересны. - person OregonGhost; 11.08.2010
comment
@OregonGhost: Правильно ли я понимаю: если 20 финализаторов занимают по 1,95 секунды каждый, это здорово, и все выполнятся - это займет 39 секунд. Если один занимает 2,05 секунды, выполнение всех остальных пропускается. Это кажется довольно сломанным. Было бы неплохо довольно грубо прервать финализатор, который занимает более 2 секунд, чтобы позволить другим работать до конца 40-секундного тайм-аута. Но затирать вещи через две секунды казалось бы неправильным. - person supercat; 24.08.2010
comment
@supercat: Я не знаю, точно ли это так, как вы описываете, я только что прочитал статью, на которую я ссылался, в которой, с другой стороны, утверждается, что поведение могло измениться с годами. Не забывайте, что вы никогда не должны полагаться на финализаторы, так что я думаю, что это нормально. Вы должны где-нибудь порезаться. Если вы думаете, что 2,05 секунды должно быть нормально, что с 2,10? 2,15? 3? 5? Вы действительно не хотите ждать 40 секунд, прежде чем приложение исчезнет, ​​это просто сеть безопасности третьего уровня (после запуска финализаторов и ожидания по 2 секунды для каждого из них). Приложениям не требуется 40 секунд для завершения работы. - person OregonGhost; 24.08.2010
comment
@OregonGhost: я думаю, что ограничение в две секунды для финализатора, вероятно, было бы в целом хорошей вещью, если бы наложение ограничения позволило бы запускать другие финализаторы; возможно, можно было бы уменьшить лимит со временем (например, каждый финализатор получает 5% времени, оставшегося до 40-секундного лимита). Что касается того, чтобы не полагаться на финализаторы, какой еще механизм будет сигнализировать объектам о сохранении своего состояния при завершении работы приложения? - person supercat; 24.08.2010
comment
@supercat: когда приложение закрывается, финализаторы все равно не запускаются. Если вы просто хотите, чтобы кто-нибудь (все ваши объекты) освободил ресурсы или сохранил свое состояние при обычном выходе, используйте IDisposable. Если у вас есть какой-то дескриптор, который следует отпустить, даже если, например, в вашем домене приложения происходит сбой, используйте SafeHandle. Мне никогда не приходилось писать ни одного финализатора в каком-либо .NET-коде, который я когда-либо писал. Деструкторы C ++ также переводятся в IDisposable.Dispose в C ++ / CLI, а не в финализатор. Из-за всего этого, я думаю, что простая система тайм-аута, используемая в CLR, хороша, хотя и ваша тоже. - person OregonGhost; 24.08.2010

Если финализатор выдает исключение, другие финализаторы не будут выполняться.

Вы также можете подавить финализаторы, если вызовете SuppressFinalizer на объект.

Из MSDN (Object.Finalize):

Метод Finalize может не работать до конца или вообще не работать в следующих исключительных случаях:

  • Другой финализатор блокируется на неопределенное время (входит в бесконечный цикл, пытается получить блокировку, которую он никогда не сможет получить, и так далее). Поскольку среда выполнения пытается запустить финализаторы до завершения, другие финализаторы могут не вызываться, если финализатор блокируется на неопределенное время.
  • Процесс завершается, не давая среде выполнения возможности выполнить очистку. В этом случае первое уведомление среды выполнения о завершении процесса - это уведомление DLL_PROCESS_DETACH.
person Oded    schedule 11.08.2010
comment
Не могли бы вы добавить источник для части исключения? - person mafu; 11.08.2010
comment
Обратите внимание, что переход в бесконечный цикл в реализации CLR означает более двух секунд, как объясняется здесь: nitoprograms.blogspot.com/2009/08/ - person OregonGhost; 11.08.2010
comment
@mafutrct - см. здесь: stackoverflow.com/questions/1538630/ - person Oded; 11.08.2010