Suspending and resuming threads for GC

First of all, suspension and resumption of threads is not really part of the GC. GC calls functions to do the suspension and the resumption as a service provided in the CLR. Other components in the CLR also use this service such as the debugger implementation. But it’s true that suspending and resuming because of the GC is the most significant usage of this service.

Secondly, how threads are suspended and resumed works the same way in Workstation GC (with or without Concurrent GC) and Server GC. Workstation GC with Concurrent GC just suspends and resumes threads more times than the other two cases.

Now let’s talk about suspension. A managed thread could be running either managed code or native code at the time. If it’s running native code which can either be from

·         the EE (Execution Engine) of the CLR – for example, EE implements some helper function for your managed call which is on the stack at the time. In this case the EE code tells the suspension code how it should be suspended. A common scenario is the EE code will wait for GC to finish so the suspension code doesn’t need to suspend it (it already suspends itself). Or

·         the native code is not from the EE, which means it’s running some native code via Interop, we don’t need to suspend this thread because it shouldn’t be doing anything with managed objects that can are not pinned. When this thread needs to return to managed code, however, it will need to check if a GC is in progress and if so it needs to wait for GC to finish.

For the managed threads that are running managed code it can be in either

§         a mode where it can be stopped at any time (because the JIT recorded enough info for each instruction) in which case it can be suspended right there. We then redirect it to some function that will make this thread wait for GC to complete. Or

·         a mode where it can’t be stopped at any time, in which case the thread’s return address will be hijacked, meaning we replace the return address by a stub which will suspend this thread. What this stub does is it will suspend this thread to wait for GC to finish.

In both case the function that was used to suspend the thread knows how to resume them correctly when GC finishes.

Resumption works much simpler. When a GC is finished, all the threads that were suspended will wake up (they were waiting on an event for GC to finish) to resume execution. 

Comments (8)

  1. Sam Gentile says:

    Only one more to go and I’ll hit the magic 100 – only took three years to get there-).  [More]

  2. Its not related to current topic so sorry for this but i wanted to ask you one question and i had no other way.

    You can remove the comment if you feel so.

    Q:How to handle multiple references to an real object

    How CLR manages the references to an object?

    I was thinking and trying to come-out with a pattern where we can dispose the object by removing all references at a time by one action so don’t need to remove[nullify] the references explicitely.

    Can you privide any pointer?

    Thanks in adavnce,

    Mahesh Devjibhai Dhola

  3. Mahesh, this is a question better answered by Krys (who owns the design guideline stuff). His blog is at You can post your question there. Off the top my head I am thinking you could give out references to the object via a class instead of directly assigning it. So you only maintain one reference to the object. Krys may have better ideas.

  4. Sergey says:

    Hi Maoni,

    Sorry for the offtopic, but I’m really stuck with my problem.

    Once in a while full garbage collection in server mode takes ~8 minutes (while usually it is about 5 seconds) without any obvious for me reason (processors are free, no swapping). I’ve described the whole situation at msdn forums:

    Could you please give a hint what could be the problem, how to identify or avoid it?

    Thanks is advance,


  5. Rob McCready says:

    I’m really late to this post (found it in search), but I’m having a hard time answering the following question:

    Does GC suspend managed threads in the entire process, or just the appdomain? I’ve been having a hard time generally finding out whether the GC keeps appdomain-by-appdomain heaps and generation quotas or whether it works on the whole process at a time,



  6. Rob, GC is per process. The suspension is also done per process. Basically (in simple terms) you can think it as all the managed threads are suspended.

  7. Rob McCready says:

    Thanks very much. That is what I figured from everything I had read, but it was surprisingly hard to find information that completely nailed it down. Most of the articles say something like "all managed threads in the /application/ are suspended", which still leaves the door open for it to be per-appdomain.

  8. Brien says:

    Hi Maoni,

    Can you detail under what circumstances the GC would need to suspend a return from a P/Invoked as you stated.

    "When this thread needs to return to managed code, however, it will need to check if a GC is in progress and if so it needs to wait for GC to finish."