Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does an object with a pending finalizer need to be collected by the GC more than one time?

I am reading the "Disposal and Garbage Collection" chapter of book C# 8.0 in a Nutshell. When it comes to finalizers, it says:

The GC identifies the unused objects for deletion, those without finalizers are deleted immediately, those with pending finalizers are kept alive and are put onto a special queue. When the garbage collection is complete and your program continues executing, the finalizer thread then starts running in parallel to the program, picking objects off that special queue and running their finalization methods.

Does this paragraph mean that an object waiting for finalization need to be collected by the GC again? I assumed it already been detected as garbage by GC, why does it need to be collected after finalization again?

like image 222
Roksana Avatar asked Mar 02 '23 01:03

Roksana


2 Answers

Well, the objects were not 'collected' the first time. They were seen to need additional processing (finalizer code needs to run) and put on the finalization queue so they could be processed separately. This ends up putting them on the 'freachable' queue, which has now resurrected the object: it is now referenced by the freachable queue and is no longer eligible for collection. It will be unreachable after the finalizer actually executes and the object is removed from the freachable queue.

(This is how it used to work, not sure if things have changed in newer .NET versions, but I'm not aware of any.)

So the object is not really 'collected' more than once, if by 'collected' we understand that the memory was reclaimed. It does, however, need additional processing and will be re-evaluated by the GC again at a later point in time.

like image 68
mtreit Avatar answered Mar 04 '23 16:03

mtreit


The GC works by traversing object graphs from GC roots. When the GC does a collection it checks for objects that have no references to it (and are therefore safe to free up).

A finalizer delays garbage collection of objects.

Why? Well the GC sees that an object is safe to be free'd up (not connected to a GC root). However, it can't free the memory if there's a finalizer that hasn't run yet.

So the GC marks the object as having a pending finalizer and does not free up that space on first pass. Nor does the GC run the finalizer at that instant (it puts it in a "pending finalizer" queue).

This is exactly why it's bad practice to use finalizers unless necessary. It delays collection. Some have a misconception that the GC runs the finalizer upon a collection pass. It does not.

When is it necessary? A good rule of thumb is if the objects references unmanaged memory (which is not handled by the GC) then you absolutely should use a finalizer to avoid memory leaks. If you're only referencing managed objects then don't.

If you do implement a finalizer I would also implement IDisposable, release any unmanaged resources on Dispose and stop the finalizer ever from running with GC.SuppressFinalize(this).

like image 26
Zer0 Avatar answered Mar 04 '23 14:03

Zer0