Зачем объекты кладутся в очередь финализации в C#
Что проверяют
Понимаете ли вы механику сборщика мусора, а не только слово «деструктор». Главное ждут услышать, почему объект с финализатором живёт дольше обычного и чем это плохо. Следом почти всегда спрашивают про IDisposable и GC.SuppressFinalize.
Как отвечать
Финализатор нужен как страховка: освободить неуправляемый ресурс (дескриптор файла, сокет, память из нативной библиотеки), если никто не вызвал Dispose. В C# он пишется как ~MyClass(), компилятор превращает это в переопределение Finalize.
Как устроено:
- регистрация при создании: объект типа с финализатором попадает в очередь финализации сразу при выделении памяти, а не когда становится ненужным. Так GC знает, за какими объектами следить;
- сборка: найдя такой объект недостижимым, GC не освобождает память, а переносит ссылку в очередь f-reachable. Объект временно снова достижим, вместе со всем, на что он ссылается;
- поток финализации: отдельный поток по одному вызывает
Finalize, порядок не гарантирован; - вторая сборка: память освобождается только на следующей сборке, а объект к тому времени обычно продвинут в старшее поколение, где сборки редкие.
Правильный путь это IDisposable и using (или using var с C# 8). В Dispose освобождаете ресурс и вызываете GC.SuppressFinalize(this), который снимает объект с очереди, и второй сборки не будет. Свой финализатор сейчас пишут редко: ресурс оборачивают в SafeHandle, у которого финализатор уже есть и написан надёжно.
Где спотыкаются
Говорят, что в очередь объект кладут, когда он умер. Регистрация происходит при создании, и поэтому массовое создание финализируемых объектов обходится дороже даже при правильном Dispose.
Обращаются в финализаторе к другим управляемым объектам. Они могли уже быть финализированы, поэтому трогать там можно только собственные неуправляемые ресурсы. Исключение из финализатора завершает процесс.
Полагаются на финализатор как на гарантию. В .NET Core и .NET 5+ финализаторы при завершении процесса не запускаются, а заблокированный поток финализации тихо копит память. Это страховка, а не замена Dispose.