8

This is an extract from a msdn article. article can be found here

There is a special runtime thread dedicated to calling Finalize methods. When the freachable queue is empty (which is usually the case), this thread sleeps. But when entries appear, this thread wakes, removes each entry from the queue, and calls each object's Finalize method. Because of this, you should not execute any code in a Finalize method that makes any assumption about the thread that's executing the code. For example, avoid accessing thread local storage in the Finalize method.

This is a question that I have asked before and I was downvoted for the same saying that there is no dedicated thread for Finalizable objects and my souce of information is wrong. If what this article explain is true than I want to know why do CLR needs a special thread for calling Finalize method ?

naveen
  • 1,016
  • 1
  • 9
  • 22
  • 2
    Might this be the same thread responsible for garbage collection? Does the language spec has any info about that? If it is the same thread where the GC runs, than your answer would be to prevent execution of other code when GC performs generation management, check for unrooted objects, etc. – Samuel Jul 03 '14 at 06:49
  • you should be vary careful relaying on articles from the year 2000, **a lot** has changed since than in the way the .Net does things, and a lot has changed in the way .Net does garbage collection in .Net 4.5 – AK_ Jul 03 '14 at 07:03
  • 1
    I'm not sure that *need* is the correct term. As an implementation *detail*, an implementation may choose to use a dedicated thread to perform finalization, but I don't think that it's a requirement of a conforming implementation. – Damien_The_Unbeliever Jul 03 '14 at 07:08
  • The only other way to do it is by picking the thread that performed the GC and have it execute the finalizers. The program must remain frozen while that happens. Which do you like better? – Hans Passant Jul 03 '14 at 07:31
  • 1
    I'd like to point out that some finalizers can take a silly amount of time - most notably, half-closed (or was it half-open?) sockets. Would you like your application to stop dead for four minutes because you forgot to explicitly dispose of one socket somewhere? But the basic point really is, that the simplest way to handle finalization is in a separate thread - you should be pretty much completely isolated from the rest of the application in your finalizer code anyway, which makes it incredibly thread-safe. You would need a reason *not* to use a thread, not the other way around. – Luaan Jul 03 '14 at 07:45

3 Answers3

3

There is nothing about what finalizers do that need the separate thread, however consider this:

  • When GC runs on generation 0 and 1, the "ephemeral" generations, managed threads are suspended
  • Concurrent or background collection can run on generation 2 after the managed threads have resumed (there's a lot of information about this in MSDN: Fundamentals of Garbage Collection)

However, a plausible naive solution would be to do the following:

  • Suspend all the threads (or possibly leave the thread that triggered GC running, just have it do GC instead)
  • Do the garbage collection, with everything this entails
  • Resume all threads

This would probably be quite simple to implement. The GC operation has free access to all the data structures related to the heaps and is free to do anything it wants, because no other thread that accesses these things are running.

However, this would make the program have "quite long" pauses from time to time, and would be quite unacceptable in most applications.

So instead the team that works on the GC has opted for the solution of suspending for the smallest possible time, suspending only when needed (generation 0 and 1 collection) while leaving the application running while generation 2 is collected. This is more difficult. Note, this is assumptions on my part, I don't have access to the actual design documentation or any solid information about this. The assumptions are based on the official documentation.

So back to the finalizer thread. These objects are already "dead" and slated for collection, so in lieu of the above design decision, why bother one of the main threads doing application work with this? Since the GC is already doing things in the background, handling finalization of dead objects in the same way seems like a good decision.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
0
  1. Finalizers are your last line of defence - if your resources are not properly disposed then somewhere in the future the CLR itself will try to accomplish the cleanup. This process is completely undeterministic - it is not RAII. It is not designed to deal with some eventhandler unhooking or something similar - it should clean the unmanaged resources your instance used and haven't properly disposed of (managed resources will be disposed even without direct finalizer, at least if there are not any circular dependencies). So there is no need for it to be executed on your worker thread.
  2. Overall garbage collection is undeterministic and unobtrusive for your program - it happens when the CLR decides to do it and you don't know about it and can't really influence it (Well, there is GC class, but nonetheless).
  3. Unmanaged resources can be quite hefty and should be disposed as fast as possible.
  4. Even if there was a need for finalizers to be executed on the same thread then how can it be actually implemented? To execute code on the thread in some arbitrary moment of time it[thread] has to provide some sort of SyncronizationContext and not everyone can provide it. So each thread would have had to provide such SyncronizationContext - not the best idea.

Taking into account all these observation dedicated thread for finalization looks like quite a logical and effective solution.

Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
0

You can improve performance by utilizing concurrency, in particular on modern processor architectures with multiple CPU cores. Garbage collection is very useful but it may have some performance impact because essentially your application will not be able to do anything while the garbage collector is rearranging the layout of objects in memory. However, any finalization can be performed in the background and that is why it is done on a seperate thread to increase performance.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256