So, what’s new in the CLR 4.0 GC?

PDC 2008 happened not long ago so I get to write another “what’s new in GC” blog entry. For quite a while now I’ve been working on a new concurrent GC that replaces the existing one. And this new concurrent GC is called “background GC”.

First of all let me apologize for having not written anything for so long. It’s been quite busy working on the new GC and other things.

Let me refresh your memory on concurrent GC. Concurrent GC has existed since CLR V1.0. For a blocking GC, ie, a non concurrent GC we always suspend managed threads, do the GC work then resume managed threads. Concurrent GC, on the other hand, runs concurrently with the managed threads to the following extend:

§It allows you to allocate while a concurrent GC is in progress.

However you can only allocate so much – for small objects you can allocate at most up to end of the ephemeral segment. Remember if we don’t do an ephemeral GC, the total space occupied by ephemeral generations can be as big as a full segment allows so as soon as you reached the end of the segment you will need to wait for the concurrent GC to finish so managed threads that need to make small object allocations are suspended.

§It still needs to stop managed threads a couple of times during a concurrent GC.

During a concurrent GC we need to suspend managed threads twice to do some phases of the GC. These phases could possibly take a while to finish.

We only do concurrent GCs for full GCs. A full GC can be either a concurrent GC or a blocking GC. Ephemeral GCs (ie, gen0 or gen1 GCs) are always blocking.

Concurrent GC is only available for workstation GC. In server GC we always do blocking GCs for any GCs.

Concurrent GC is done on a dedicated GC thread. This thread times out if no concurrent GC has happened for a while and gets recreated next time we need to do concurrent GC.

When the program activity (including making allocations and modifying references) is not really high and the heap is not very large concurrent GC works well – the latency caused by the GC is reasonable. But as people start writing larger applications with larger heaps that handle more stressful situations, the latency can be unacceptable.

Background GC is an evolution to concurrent GC. The significance of background GC is we can do ephemeral GCs while a background GC is in progress if needed. As with concurrent GC, background GC is also only applicable to full GCs and ephemeral GCs are always done as blocking GCs, and a background GC is also done on its dediated GC thread. The ephemeral GCs done while a background GC is in progress are called foreground GCs.

So when a background GC is in progress and you’ve allocated enough in gen0, we will trigger a gen0 GC (which may stay as a gen0 GC or get elevated as a gen1 GC depending on GC’s internal tuning). The background GC thread will check at frequent safe points (ie, when we can allow a foreground GC to happen) and see if there’s a request for a foreground GC. If so it will suspend itself and a foreground GC can happen. After this foreground GC is finished, the background GC thread and the user threads can resume their work.

Not only does this allow us to get rid of dead objects in young generations, it also lifts the restriction of having to stay in the ephemeral segment – if we need to expand the heap while a background GC is going on, we can do so in a gen1 GC.

We also made some performance improvement in background GC which does better at doing more things concurrently so the time we need to suspend managed threads is also shorter.

We are not offering background GC for server GC in V4.0. It’s under consideration – we recognize how important it is for server applications (which usually have much larger heaps than client apps) to benefit from smaller latency but the work did not fit in our V4.0 timeframe. For now for server applications, I would recommend you to look at the full GC notification feature we added in .NET 3.5 SP1. It’s explained here: http://msdn.microsoft.com/en-us/library/cc713687.aspx. Basically you register to get notified when a full GC is approaching and when it’s finished. This allows you to do software load balancing between different server instances – when a full GC is about to happen in one of the server instances, you can redirect new requests to other instances.

This question regards what might be a bug in .NET Framework 1.1, but I think it applies here as it regards a multi-threaded app and the GC. After changing the system time (to speed up events,) some of my weak references are lost, although the original object is still alive. Why would this happen? Can changing the system time corrupt the GC?

Egg on face. My problem is clearly an application bug as I tracked down an inconsistency in what Target was being assigned. Sorry, I have a policy (from previous experience) to go to MS as a last resort, but you know how we programmers sometimes lose our senses.

Anyway, maybe I’m out of the times or uninformed here, but I would like to see the GC tell us ONE place where objects are still alive: for debugging purposes. The objects can be registered separately with the GC, and then every 3 seconds or so after it completes its cleaning, raise an event that provides this information. Each event handler should be given its own thread to avoid one event handler from unfairly blocking the others. Where objects are alive can be given in increments.

First new and notable with the new Graffiti blog. WCF/Cloud Services Aaron has his latest in his series of WCF screencasts , this time showing how to host WCF services within traditional Windows services Aaron also has a geekSpeak webcast on Cloud Services

This is a bit unrelated to the topic, but I see an application using server GC where "% time in GC" perf counter keeps stuck at the same value for minutes after running for a bit and all other processing seems to stop. CPU spins at 100% on one processor. This is triggered by a Gen 0 collection, so I wonder if this is a GC related issue or not.

"We are not offering background GC for server GC in V4.0. It’s under consideration – we recognize how important it is for server applications (which usually have much larger heaps than client apps) to benefit from smaller latency but the work did not fit in our V4.0 timeframe. For now for server applications, I would recommend you to look at the full GC notification feature we added in .NET 3.5 SP1. It’s explained here: http://msdn.microsoft.com/en-us/library/cc713687.aspx. Basically you register to get notified when a full GC is approaching and when it’s finished. This allows you to do software load balancing between different server instances – when a full GC is about to happen in one of the server instances, you can redirect new requests to other instances."

Maoni,

First of all, congrats! Your blog is really interesting. Every time I look at it, I find some interesting news.

Concerning to the server GC, it would be great to have such behavior (background gc) within.

Unfortunatelly, for real-time/time-critical applications (on wich every microsecond is really really precious), the cost of changing to another process after a GC notification is too expensive to be considered. More than that, an extra overhead should be added to the application in order to synchronize both process with the same state information (even shared memory has a little cost).

I just wanted to say this is a big step in the right direction for allowing .net to meet the requirements of the software I work on. I am extremely excited to see the Server mode support background GC. Any idea when this could be seen in any betas?

Have you guys done any work on the pinning problem with P/Invoke (and thus sockets)? By now it’s one of the most famed issues that people are seeing when they implement large-scale socket servers – although I don’t know if you guys have admitted it yet :).

The buffer pool is a great idea, however, I basically need to do it at the bottom level (copy to a pool-managed buffer just before a read/write to the socket) because these buffers don’t traverse SecureStreams etc. So I was wondering if I would be able to take this ‘hackish’ code out in 4.0?

I've been reading a lot about GC and specifically Concurrent GC and Background GC.

I need some clarifications please:

1) Jeffry Ritcher says in CLR via C# 3.0 that Gen 0 Starts as 256KB, Gen 1 starts as 2MB and Gen 2 starts as 10MB. 256KB + 2MB doesnt equal 16MB you say is for ephemral segmant, so I would like some clarification on this.

2) Could you explain or provide a link explaining the segmants swapping? Ritcher doesnt note that in his book, and I havn't managed to found clear explanation about this online.