Glossary / Finalizers

Finalizers

A finalizer is a nondeterministic cleanup hook that the garbage collector may invoke before reclaiming an object. It is primarily a safety net for releasing unmanaged resources when deterministic disposal was omitted; finalizers are not guaranteed to run promptly or at process shutdown and should not be ordinary destructors.

Lifetime and resurrection

A finalizer is declared as ~TypeName() and has no parameters or accessibility modifier. An object with a finalizer typically requires extra GC work: it is queued for finalization, kept alive until processing, and may be resurrected if code makes it reachable again. Exceptions escaping finalizers can terminate the process in many runtime configurations. Finalization order among related objects is not a reliable dependency mechanism.

Implement IDisposable for deterministic cleanup and use SafeHandle for native handles. A finalizer is appropriate only when the type directly owns an unmanaged resource and needs a fallback; follow the dispose pattern and suppress finalization after successful disposal. Do not add one merely because a class owns another managed disposable object.

Engineering guidance

Prefer using/await using, IDisposable, and safe-handle abstractions. Keep finalizers minimal, non-throwing, idempotent, and independent of other finalizable objects. Test resource release through disposal; do not rely on GC timing.

Interview questions

  1. Are finalizers deterministic? No; GC timing and process shutdown do not guarantee prompt invocation.
  2. When is one justified? As a safety net for directly owned unmanaged resources, often through SafeHandle.
  3. Why do finalizable objects cost more? They need additional queueing and collection processing.
  4. Can finalizers throw? They should not; escaping exceptions can be process-fatal.
  5. What should normal cleanup use? IDisposable/IAsyncDisposable and using scopes.

References