Garbage collection and finalizers: thinner points

Answering another question about SO and the subsequent discussion of comments, I ran into a wall at a point that I don't know about.

Correct me at any point where I am astray ...

When the garbage collector collects an object, it calls this object finalizer in a separate thread (unless the finalizer has been suppressed, for example, using the Dispose() method). When collecting, GC pauses all threads except the thread that caused the collection (collecting background aside).

What is not clear:

  • Does the garbage collector plan to finalize the finalizer at this object before it is collected?
  • If not, does the thread suspend during run time?
  • If he expects what will happen if the finalizer enters a lock held by one of the suspended threads? Is the finalizer blocked? (In my answer, I argue that this is a bad design, but I could see cases where this could happen)

TIA
James

Link to the original question:
.NET GC Accessing a synchronized object from a finalizer

+10
garbage-collection c # finalizer
Mar 07 '11 at 18:00
source share
3 answers

Does the garbage collector collect until the finalizer at this facility completes before collecting it?

Your question is a bit ambiguous.

When the GC encounters a dead object that needs to be completed, it abandons the attempt to return the dead object store. Instead, it places the object in the queue of "objects that I know need to be completed," and treats this object as live until the finalizer thread executes with it.

So, yes, the GC "waits" until the finalizer is complete before the repository is restored. But he does not wait synchronously. It looks like you are asking: "Is the GC synchronously called by the finalizer?" No, he queues the facility, which will be completed later, and continues the truck. GC wants to quickly complete the task of freeing up memory for garbage and compacting so that the program can resume work as soon as possible. He is not going to stop to deal with some piercing object that needs attention before it is cleaned. He puts this object in the queue and says: "Be calm, and the finalizer thread will deal with you later."

Later, the GC will check the object again and say, "Are you still dead? And is your finalizer running?" If the answer is yes, the object is returned. (Remember that the finalizer can return a dead object to a living one, try never to do this. As a result, nothing nice happens.)

Does it disable threads during finalizer execution?

I believe that the GC is thawing the threads it froze and signals the finalizer thread "hey, you have a job." Therefore, when the finalizer thread starts running, threads that have been frozen by the GC start again.

Perhaps there should be thawed threads, since the finalizer may need the call to be bound to the user thread in order to free up the resource associated with the thread. Of course, some of these user threads may be blocked or frozen; threads can always be blocked by something.

What happens if the finalizer enters a lock held by one of the suspended threads? Is the thread finalizer locked?

You are daughters. There is nothing magical about the finalizer thread that prevents it from being blocked. If the user thread is waiting for a lock fetched by the finalizer thread, and the finalizer thread is expecting a lock fetched by the user thread, then you have a dead end.

Examples of dead ends in the finalizer abound. Here is a good article on one of these scenarios, with tons of links to other scenarios:

http://blogs.microsoft.co.il/blogs/sasha/archive/2010/06/30/sta-objects-and-the-finalizer-thread-tale-of-a-deadlock.aspx

As the article says: finalizers are an extremely complex and dangerous cleaning mechanism, and you should avoid them, if possible . It is incredibly easy to get the finalizer wrong and very difficult to get everything right.

+42
Mar 07 '11 at 18:27
source share

Objects containing a finalizer tend to live longer. When GC marks an object with finalizer as garbage during collection, it will not collect this object (for now). The GC will add this object to the finalizer queue, which will be launched after the GC completes. The consequence of this is that, since this object is not assembled, it moves on to the next generation (and also applies to all objects).

GC pauses all current threads. On the other hand, the finalizer thread will run in the background while the application continues to run. The finalizer names all completion methods for all objects that are registered to complete. After starting the finalizer method on the object, the object will be removed from the queue, and from this point on the object (and, possibly, all the objects that it still refers to) is garbage. The next collection, which clears the generation objects of this object, will (finally) delete this object. Since the objects that live in generation 2 are collected about 10 times less than the objects that live in generation 1, and the gene 1 is ten times smaller than gene 0, it may take some time for this object to be finally assembled garbage.

Since a finalizer thread is just a thread that manages managed code (it calls finalizers), it can block even deadlock. Because of this, it is important to do as little as possible in finalization methods. Since the finalizer is a background thread, an unsuccessful finalization method can even knock down the entire AppDomain (yuck!).

You could say that this design is unsuccessful, but if you think about it, other projects in which the system effectively clears our mess are hard to imagine.

So, to answer your questions:

  • Yes, only after removing the object from the finalizer queue will the object be garbage and the GC will collect it.
  • The GC pauses all threads, even the finalizer queue.
  • The finalizer queue may be blocked. Block as little as possible inside completion methods.
+4
Mar 07 '11 at 18:30
source share

The easiest way to think of the garbage collector is to divide objects into four groups:

  • Those that are not accessible to any root object;
  • Those that are available from the list of live finalizable objects, but not from any other embedded object;
  • Those that are in the list of live finalizable objects, but are also accessible through some root object other than this list.
  • Those that are not included in the list of live finalizable objects, but are accessible through some embedded object, different from this list.

When the garbage collector starts, objects like # 1 disappear. Objects # 2 are added to the list of objects that need imminent finalization, and are removed from the list of "live finalized objects" (thus, they become category 4 objects). Please note that the list of objects that need to be completed is a regular root link, so the objects in this list cannot be collected while they are located, but if no other linked link is created by the time the finalizer finishes, the object will be moved to category # 1.

+3
Mar 07 2018-11-18T00:
source share



All Articles