OdeToCode IC Logo

Server Or Workstation Garbage Collection?

Friday, July 16, 2004
I did some experimentation this evening because I read something that struck me as odd in a comment on Scott H’s blog.

First, some background. There are two versions of the garbage collector for .NET. The garbage collector optimized for multi-processor machines (packaged in MSCorSvr.dll), and the workstation garbage collector (packaged in MsCorWks.dll). I can see who is running the workstation garbage collector on a Win2003 machine using tasklist from the command line:

tasklist /m mscorwks.dll
Image Name                   PID Modules
========================= ====== ==================
OUTLOOK.EXE                 3352 mscorwks.dll
mmc.exe                     2084 mscorwks.dll
w3wp.exe                    3436 mscorwks.dll

One of the comments suggested going into the .NET Configuration 1.1 MMC in Administrative Tools, right clicking on My Computer, and setting the garbage collection mode to “Run in foreground for server applications”.

This struck me as odd, because in doing some review work for the Performance and Scalability Guide I found out that choosing the garbage collector implementation with a .config file setting was not going to be a runtime feature until the Whidbey timeframe. I tried this configuration option and reset IIS. After hitting a local web application and running taskmgr again my ASP.NET worker process (W3WP.EXE) was still showing mscorwks.dll loaded, not mscorsvr.dll

After a little more digging I discovered the MMC toggles the gcConcurrent element in machine.config:

<runtime> ...
    <gcConcurrent enabled="false" />

It turns out the gcConcurrent setting does not change which garbage collector loads. gcConcurrent only has an impact on the workstation (MsCorWks.dll) implementation of the garbage collector (it is effectively ignored by the server implementation), and furthermore only changes the GC behavior on multiprocessor machines.

With the setting enabled the garbage collector uses an additional thread to build a graph of unreachable objects. The rule of thumb is, gcConcurrent=”true” (default setting) will provide for a more responsive application, but can also let the working set (memory usage) grow larger. You’d have to carefully test an application to see if disabling gcConcurrent actually helps an application’s performance or memory usage. The most detailed source of information I’ve found in one place on this subject is Jeffrey Richter’s book.

<SARCASM>To turn this into a spirited debate, I want to point out that developers who use MsCorSvr.dll on average earn 26% more than developers using MsCorWks.dll. </SARCASM>

Honestly, with all the cycles the .NET community burns on language debates, we could have built another language.