Welcome to MSDN Blogs Sign in | Join | Help

Maoni's WebLog

CLR Garbage Collector
Using GC Efficiently – Part 2

In this article I’ll talk about different flavors of GC, the design goals behind each of them and how they work differently from each other so you can make a good decision of which flavor of GC you should choose for your applications.

 

Existing GC flavors in the runtime today

 

We have the following flavors of GC today:

 

1)      Workstation GC with Concurrent GC off

2)      Workstation GC with Concurrent GC on

3)      Server GC

 

If you are writing a standalone managed application and don’t do any config on your own, you get 2) by default. This might come as a surprise to a lot of people because our document doesn’t exactly mention much about concurrent GC and sometimes refers to it as the “background GC” (while refering Workstation GC as “foreground GC”).

 

If your application is hosted, the host might change the GC flavor for you.

 

One thing worth mentioning is if you ask for Server GC and the application is running on a UP machine, you will actually get 1) because Workstation GC is optimized for high throughput on UP machines.

 

Design goals

 

Flavor 1) is designed to achieve high throughput on UP machines. We use dynamic tuning in our GC to observe the allocation and surviving patterns so we adjust the tuning as the program runs to make each GC as productive as possible.

 

Flavor 2) is designed for interactive applications where the response time is critical. Concurrent GC allows for shorter pause time. And it trades some memory and CPU to achieve this goal so you will get a slightly bigger working set and slightly longer collection time.

 

Flavor 3), as the name suggests, is designed for server applications where the typical scenario is you have a pool of worker threads that are all doing similar things. For example, handling the same type of requests or doing the same type of transactions. All these threads tend to have the same allocation patterns. The server GC is designed to have high throughput and high scalibility on multiproc machines.

 

How they work

 

Let’s start with Workstation GC with Concurrent GC off. The flow goes like this:

 

1)      A managed thread is doing allocations;

2)      It runs out of allocations (and I’ll explain what this means);

3)      It triggers a GC which will be running on this very thread;

4)      GC calls SuspendEE to suspend managed threads;

5)      GC does its work;

6)      GC calls RestartEE to restart the managed threads;

7)      Managed threads start running again.

 

In step 5) you will see that all managed threads are stopped waiting for GC to complete if you break into the debugger at that time. SuspendEE isn’t concerned with native threads so for example if the thread is calling out to some Win32 APIs it’ll run while the GC is doing it work.

 

For the generations we have this concept called a “budget”. Each generation has its own budget which is dynamically adjusted. Since we always allocate in Gen0, you can think of the Gen0 budget as an allocation limit that when exceeded, a GC will be triggered. This budget is completely different from the GC heap segment size and is a lot smaller than the segment size.

 

The CLR GC can do either compacting or non compacting collections. Non compacting, also called sweeping, is cheaper than compacting that involves copying memory which is an expensive operation.

 

When Concurrent GC is on, the biggest difference is with Suspend/Restart. As I mentioned Concurrent GC allows for shorter pause time because the application need to be responsive. So instead of not letting the managed threads run for the duration of the GC, Concurrent GC only suspends these threads for a very short period of times a few times during the GC. The rest of the time, the managed threads are running and allocating if they need to. We start with a much bigger budget for Gen0 in the Concurrent GC case so we have enough room for the application to allocate while GC is running. However, if during the Concurrent GC the application already allocated what’s in the Gen0 budget, the allocating threads will be blocked (to wait for GC to finish) if they need to allocate more.

 

Note since Gen0 and Gen1 collections are very fast, it doesn’t make sense to have Concurrent GC when we are doing Gen0 and Gen1 collections. So we only consider doing a Concurrent GC if we need to do a Gen2 collection. If we decide to do a Gen2 collection, we will then decide if this Gen2 collection should be concurrent or non concurrent.

 

Server GC is a totally different story. We create a GC thread and a separated heap for each CPU. GC happens on these threads instead of on the allocating thread. The flow looks like this:

 

1)      A managed thread is doing allocations;

2)      It runs out of allocations on the heap its allocating on;

3)      It signals an event to wake the GC threads to do a GC and waits for it to finish;

4)      GC threads run, finish with the GC and signal an event that says GC is complete (When GC is in progress, all managed threads are suspended just like in Workstation GC);

5)      Managed threads start running again.

 

Configuration

 

To turn Concurrent GC off, use

 

<configuration>

    <runtime>

        <gcConcurrent enabled="false"/>

    </runtime>

</configuration>

 

in your application config file.

 

To turn Server GC on, use

 

<configuration>

    <runtime>

        <gcServer enabled=“true"/>

    </runtime>

</configuration>

 

in your application config file, if you are using Everett SP1 or Whidbey. Before Everett SP1 the only supported way is via hosting APIs (look at CorBindToRuntimeEx).

Posted: Saturday, September 25, 2004 2:58 PM by maoni
Filed under:

Comments

Dmitriy Zaslavskiy said:

Hi,
Will concurrent GC block all managed threads during compact phase?
# September 27, 2004 10:59 AM

Chris Lyon's WebLog said:

# September 27, 2004 7:25 PM

Chris Lyon's WebLog said:

# September 27, 2004 7:28 PM

Josh Williams said:

# October 28, 2004 1:16 PM

Maoni's WebLog said:

# November 5, 2004 1:33 AM

Maoni's WebLog said:

# November 5, 2004 1:34 AM

Sam Gentile's Blog said:

# December 21, 2004 6:34 AM

Sam Gentile's Blog said:

# December 21, 2004 2:51 PM

JCooney.NET said:

# January 31, 2005 7:27 AM

Josh Carlisle - .Net Brain Freeze said:

# March 10, 2005 11:00 AM

Josh Carlisle - .Net Brain Freeze said:

# March 10, 2005 11:57 AM

Josh Carlisle - .Net Brain Freeze said:

# March 10, 2005 11:57 AM

Yun Jin's WebLog said:

Question: How many threads does a typical managed process have when it just starts to run?&amp;nbsp;&amp;nbsp;...
# July 5, 2005 1:05 PM

Yun Jin's WebLog said:

Question: How many threads does a typical managed process have when it just starts to run?&amp;nbsp;&amp;nbsp;...
# July 5, 2005 1:09 PM

Yun Jin's WebLog said:

Question: How many threads does a typical managed process have when it just starts to run?&amp;nbsp;&amp;nbsp;...
# July 12, 2005 2:32 PM

Steve Hebert's Development Blog said:

I previously blogged about a set must-read garbage collection articles&amp;nbsp;and issues around directly...
# July 26, 2005 5:52 PM

Rico Mariani's Performance Tidbits said:

I'm often asked &quot;What's new in Whidbey&quot; and so I thought I'd put together this (very) brief list of some...
# July 27, 2005 9:11 PM

Rico Mariani's Performance Tidbits said:

I'm often asked &quot;What's new in Whidbey&quot; and so I thought I'd put together this (very) brief list of some...
# July 27, 2005 9:15 PM

Rico Mariani's Performance Tidbits said:

I'm often asked &quot;What's new in Whidbey&quot; and so I thought I'd put together this (very) brief list of some...
# July 27, 2005 9:16 PM

C#, VS Deployment and all geek talk said:

# August 18, 2005 12:33 PM

Gaurav's Database... said:

Using GC Efficiently – Part 1
Using GC Efficiently – Part 2
Using GC Efficiently – Part 3
Using...
# August 24, 2005 1:52 PM

Yun Jin's WebLog said:

Question: How many threads does a typical managed process have when it just starts to run?&amp;nbsp;&amp;nbsp;...
# August 28, 2005 3:44 PM

Maoni's WebLog said:

In Using GC Efficiently – Part 2 I talked about different flavors of GC that exist in the CLR and how...
# March 1, 2006 1:44 AM

Eric Gunnerson's C# Compendium said:

Spending lots of time on C++ means I haven't been paying as much attention to managed code as I did in...
# May 11, 2006 3:40 PM

.Net Adventures said:


Using GC
Efficiently Part 1Maoni explains the cost of things so you can make good
decisions in...
# May 14, 2006 8:18 AM

Jeorge Lukasing said:

Very many thanks for a good work. Nice and useful. Like it!
# August 27, 2006 4:46 AM

Maoni's WebLog said:

In Using GC Efficiently – Part 2 I talked about different flavors of GC that exist in the CLR and how

# November 8, 2006 8:07 PM

Maoni's WebLog said:

Certainly that’s one of the most frequently asked questions I get (at the PDC too!). So since PDC already

# November 8, 2006 8:07 PM

Romanson said:

Hallo! Ich habe die Seite vorhin gerade entdeckt und muss dir wirklich ein Kompliment aussprechen!

# February 4, 2007 2:06 PM

chew said:

Hi Maoni,

Do you think the used GC in .Net has robbed its suitability in high performance computing applications, considering the fact that GC will suspend all managed threads and perform compacting of memory?

chew

# May 13, 2007 12:55 PM

maoni said:

chew, no. Why do you think that just because GC suspends threads and compact memory?

# May 15, 2007 9:10 AM

Maoni's WebLog said:

As 64-bit machines become more common, the problems we need to solve also evolve. In this post I’d like

# May 15, 2007 9:45 AM

chew said:

Hi maoni,

Correct me if I'm wrong. I'm also hoping .Net is the choice for high performance computing. Unfortunately, in the programming forums I visited thus far, most people think that .Net is not the suitable for high performance computing. Unmanaged code is still the preferred choice for high performance computing.

If you think GC is not the hindering factor, are you trying to say there are other factors in .Net that made it not suitable? Or do you agree .Net is definitely suitable for high performance computing? I'm been visiting forums and reading papers, hoping to get a convicing answer but to no avail so far. Appreciate if you could help out.

chew    

# May 16, 2007 10:21 AM

http://isdc.net said:

Vse promolchat nikto ne skazhe. Vartan Teige.

# June 20, 2007 5:27 PM

roy ashbrook said:

Ah. Garbage Collection... how I love and hate thee. =P I think one sad thing about programming in .net

# June 22, 2007 12:40 AM

roy ashbrook said:

Ah. Garbage Collection... how I love and hate thee. =P I think one sad thing about programming in .net

# June 22, 2007 12:43 AM

Fuziness and Cognizance... said:

There were a lot of question on good reference material for .NET (books and online). Here is a consolidated

# September 11, 2007 2:49 AM

Mo said:

Hi Maoni,

Which one would be best suited for SharePoint environment. Afterall MOSS 2007 is .Net 2.0 application only. So would it be helpful to put the ServerGC setting or Concurrent GC On in web.config file? Please advise.

Thanks,

Mo

# January 22, 2008 3:47 PM

maoni said:

Mo, can you elaborate what kind of environment "SharePoint environment" is?

# January 22, 2008 8:23 PM

Deepan said:

I have a basic question ... If two .net applications are running then each will have its own GC heap, stack etc. just like any windows process .... Is this understanding correct?

Now will there be separate GC thread for each .net application. If this is not the case and there is a single thread handling GC of all running applications, then does that imply that GC is triggered at the same time for all the applications.

Please throw some more light on this. It would be nice if you can refer some article that explains the GC considering that multiple managed applications are running together.

# January 29, 2008 4:30 AM

maoni said:

Deepan, yes each process will have its own GC heap and stacks.

GC is per process, which means the GC heap from one process is separated from another process; and if you are server GC for 2 managed processes they would each have their own server GC threads; and since it's per process, GCs from different processes are triggered on each process's own schedule.

GC is sensitive to the memory pressure on the *machine*.

# January 30, 2008 1:06 AM

Deepan said:

Thanks for the info.... just wanted to clarify my understanding further ... i think irrespective of the type of GC (Server/workstation), each .net application will have its own process space where a separate GC thread will take care of garbage collection for that process.

# January 30, 2008 3:49 AM

maoni said:

Deepan, yes each .net app will have its own process address space and GC works per process. There isn't necessarily a separated GC thread since GC could happen on the user thread that triggered the GC.

# February 13, 2008 6:43 PM

Wdyyyhoc said:

Open this post and read what I think about that:,

# June 9, 2008 11:44 PM

langolier said:

Hello all,

I have a big dictionary contains lots of data.

What I do is set the reference to this same dictionary as null and then calling the Collect() method, but it doesnt release any memory. On the other hand, when I previously call the Clear() method on the dictionary, the memory is released (on calling GC.Collect(), Clear() by itself doesn't do the trick). On the third hand :-) If I enclose the GC.Collect() call inside an infinite loop, calling it many times the memory gets freed on the very first time(!!) the GC.Collect() is called! But, if I place a finite loop, no mather how big, the memory is never released :-( Even if I place an infinite loop not obviously infinite to the compiler (something like for(int nX = 0;nX > -1;++nX) GC.Collect(); ) the memory doesn't get released. Can anyone shed some light on this ? Maoni, could you please state the rules that lead to this odd behavior of the GC.Collect() method...? I have no finalizers. I've lost days trying to figure out  the exact mechanism, because I have some more or less serious problems with memory usage. Any help deeply appreciated

Best,

Langolier

# June 27, 2008 11:21 AM

All Your Base Are Belong To Us said:

GC flavors are a static performance optimization for the .NET garbage collector.&#160; Under various

# August 10, 2008 12:10 PM

maoni said:

Langolier, you can set a breakpoint on the GC.Collect method and do a !gcroot sos command on the object you are interested in see who has references to it. When you call GC.Collect() GC doesn't participate in determining who's live and who's dead - other CLR components, like the stackwalker, determine the liveness of objects.

# October 14, 2008 7:13 PM

Sudeep said:

Maoni,

How can I find out if I have concurrent GC or non-concurrent GC for an ASP.net app hosted in an IIS process - w3wp.exe running on a UP box? !eeversion from SOS only indicates if its server or workstation mode.

Thanks

# December 30, 2008 11:37 PM

Scott Dorman's Blog said:

Note : This entry was originally posted on 9/14/2008 5:16:11 PM. I present at a lot of the local Florida

# January 10, 2009 6:40 PM

iwebthereforeiam said:

An ancient article on using the .NET garbage collector. Using GC Efficiently - Part 2...

# March 14, 2009 11:58 AM

daveblack said:

Is there a way to determine, either programmatically or not, which version of the GC is being used?

# May 28, 2009 11:58 AM

daveblack said:

I just found the System.Runtime.GCSettings.IsServerGC property to programmatically tell what mode the GC is in.

However, my real question is...what decides the mode that the GC should run in?  I was always under the impression that the .NET Framework running on a "server OS" would use "Server GC" and any non-server OS would use the Workstation GC.  I see that the default setting for "gcServer" is disabled.

Do I need to explicitly set the <gcServer enabled=“true"/> for .NET 3.5 on Windows Server 2003 R2 SP2 if I want to use Server GC?

# May 28, 2009 12:23 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker