<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Chris Lyon's WebLog : GC</title><link>http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx</link><description>Tags: GC</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>New In Orcas Part 3: GC Latency Modes</title><link>http://blogs.msdn.com/clyon/archive/2007/03/12/new-in-orcas-part-3-gc-latency-modes.aspx</link><pubDate>Mon, 12 Mar 2007 22:10:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1867061</guid><dc:creator>clyon</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/clyon/comments/1867061.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=1867061</wfw:commentRss><description>&lt;P&gt;As you may know, there are different GC modes to choose from depending on the type of application you’re using:&amp;nbsp; Server GC, Workstation GC, and Concurrent GC (&lt;A class="" href="http://blogs.msdn.com/clyon/archive/2004/09/08/226981.aspx" mce_href="http://blogs.msdn.com/clyon/archive/2004/09/08/226981.aspx"&gt;more info&lt;/A&gt;).&amp;nbsp; These settings are process-wide, set at the beginning of the process.&amp;nbsp; Once the GC mode is set, it cannot be changed.&amp;nbsp; &lt;BR&gt;In Orcas, we’ve added the concept of GC Latency Modes that while process-wide, can be changed during the lifetime of the process to meet an application’s needs.&lt;BR&gt;The Latency Modes can be accessed as new properties onto the GCSettings class:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;CODE&gt;System.Runtime.GCLatencyMode System.Runtime.GCSettings.LatencyMode { get; set; } &lt;/CODE&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The values for GCLatencyMode are Batch, Interactive and LowLatency.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Batch:&amp;nbsp; This mode is designed for maximum throughput, at the expense of responsiveness.&amp;nbsp;&amp;nbsp; It is best for applications with no UI or server-side operations and is equivalent to Workstation GC without Concurrent GC.&amp;nbsp;&amp;nbsp; If Concurrent GC is enabled, switching to Batch mode will prevent any further concurrent collections.&amp;nbsp; This is the only valid mode for Server GC.&lt;/LI&gt;
&lt;LI&gt;Interactive:&amp;nbsp; This mode balances responsiveness with throughput.&amp;nbsp; It is designed for applications with UI and is the default Latency Mode, equivalent to Workstation GC with Concurrent GC.&amp;nbsp;&amp;nbsp; This mode is not available on Server GC.&amp;nbsp;&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;LowLatency:&amp;nbsp; This mode is meant for short-term, time-sensitive operations where interruptions from the GC may be disruptive, like animation rendering or data acquisition functions.&amp;nbsp; This mode is not available on Server GC.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;How does LowLatency mode work?&lt;/P&gt;
&lt;P&gt;When you set the latency mode to LowLatency, the GC will perform almost no generation 2 collections, nor will it start any new concurrent collections.&amp;nbsp; Since generation 2 is unbounded and can become very large, collecting it can cause your managed threads to pause for short amounts of time.&amp;nbsp; This can be unacceptable for certain scenarios.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;To be clear, I’m not talking about real-time application requirements, rather requirements that a short-running block of code run smoothly with minimal interruptions from the runtime.&amp;nbsp; LowLatency mode is not real-time mode.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;I mentioned above that in LowLatency mode, the GC will perform almost no most generation 2 collections, but there are situations when it will.&amp;nbsp; As we know, there are three things that cause the GC to perform a collection (&lt;A class="" href="http://blogs.msdn.com/maoni/archive/2004/06/15/156626.aspx" mce_href="http://blogs.msdn.com/maoni/archive/2004/06/15/156626.aspx"&gt;more info&lt;/A&gt;):&lt;BR&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Allocation exceeds the Gen0 threshold – normally, these collections can escalate into full heap collections.&amp;nbsp; With LowLatency, generation 1 is the maximum generation that will be collected, possibly promoting objects to generation 2.&lt;/LI&gt;
&lt;LI&gt;System.GC.Collect is called – this will continue to work as expected.&amp;nbsp; If you specify to collect generation 2, the GC will honor your request regardless of the Latency Mode.&lt;/LI&gt;
&lt;LI&gt;System is in low memory situation – the OS has raised an event telling the runtime that it is low on system memory.&amp;nbsp; In this ase the GC will perform a generation 2 collection to attempt to free memory.&amp;nbsp; The alternative is to allow the OS to begin paging which will generally have worse pause times than a full collection.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;How to safely use LowLatency mode&lt;/P&gt;
&lt;P&gt;As you might have guessed, since generation 2 is rarely collected, OutOfMemoryExceptions are more likely under LowLatency mode.&amp;nbsp; Here are some guidelines to follow to avoid potential problems:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Keep the amount of time spent in LowLatency as short as possible.&amp;nbsp; Remember, you’re changing the behavior of the GC, which can lead to sub-optimal performance in the long-run.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;While in LowLatency mode, minimize the number of allocations you make, in particular allocations onto the Large Object Heap and pinned objects.&lt;/LI&gt;
&lt;LI&gt;Be mindful of other threads that could be allocating.&amp;nbsp; Remember, these settings are process-wide, so you could generate an OutOfMemoryException on any thread that may be allocating.&lt;/LI&gt;
&lt;LI&gt;Wrap the LowLatency code in a CER (&lt;A class="" href="http://blogs.msdn.com/bclteam/archive/2005/06/14/429181.aspx" mce_href="http://blogs.msdn.com/bclteam/archive/2005/06/14/429181.aspx"&gt;more info&lt;/A&gt;).&lt;/LI&gt;
&lt;LI&gt;Remember to set the latency mode back to avoid hard-to debug OutOfMemoryExceptions later.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Here’s a code sample of how to use LowLatency mode&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;CODE&gt;
&lt;P&gt;// preallocate objects here&lt;BR&gt;GCLatencyMode oldMode = GCSettings.LatencyMode;&lt;BR&gt;RuntimeHelpers.PrepareConstrainedRegions();&lt;BR&gt;try&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCSettings.LatencyMode = GCLatencyMode.LowLatency;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // perform time-sensitive actions here&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; minimize:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -all allocations, especially LOH allocations&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -pinning&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -allocations on other threads&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;BR&gt;}&lt;BR&gt;catch (ApplicationException)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // catch any exceptions you expect your application to throw&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // perform cleanup code&lt;BR&gt;}&lt;BR&gt;finally&lt;BR&gt;{&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // always set the mode back!&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCSettings.LatencyMode = oldMode; &lt;BR&gt;}&lt;/P&gt;&lt;/CODE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Remember, this mode can cause failures in your application, so please use good judgment when using it.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1867061" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/clyon/archive/tags/Orcas/default.aspx">Orcas</category></item><item><title>New In Orcas Part 2: GC Collection Modes</title><link>http://blogs.msdn.com/clyon/archive/2007/03/07/new-in-orcas-part-2-gc-collection-modes.aspx</link><pubDate>Thu, 08 Mar 2007 01:14:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1831076</guid><dc:creator>clyon</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/clyon/comments/1831076.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=1831076</wfw:commentRss><description>&lt;P&gt;In Orcas we’ve added an overload to System.GC.Collect():&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;CODE&gt;void System.GC.Collect(int generation, System.GCCollectionMode mode)&lt;/CODE&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Where generation is the highest generation to collect (from 0 to System.GC.MaxGeneration) and mode can be:&lt;BR&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Default:&amp;nbsp; the same behavior if you called GC.Collect without specifying the mode.&amp;nbsp; Currently this is the same behavior as Forced, but this is subject to change in future versions of the runtime.&lt;/LI&gt;
&lt;LI&gt;Forced:&amp;nbsp; guarantees a collection occurs for all the generations up to and including generation.&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;Optimized:&amp;nbsp; this mode will tell the GC to only collect if it determines that a collection will be productive.&amp;nbsp; In this case, “productive” is determined by a number of factors, including amount of memory considered garbage, heap fragmentation, etc.&amp;nbsp; The exact formula is subject to change between CLR releases.&amp;nbsp; If the GC decides a collection will not be productive, then the call will have no effect.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;When should we use these new modes?&lt;/P&gt;
&lt;P&gt;Calling GC.Collect is generally discouraged, but as Rico points out &lt;A class="" href="http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx" mce_href="http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx"&gt;here&lt;/A&gt;, there are legitimate circumstances where you know there is a large number of objects you’ll never need again.&amp;nbsp; For example, at the end of a game level, when a custom Form is closed, or when a web form is finished, there may be a number of long-lived objects in generation 2 that are now dead.&amp;nbsp; By calling an Optimized collection at this point you give the GC a chance to evaluate the heap, and have it decide if a collection will free enough memory to be worth it. &lt;/P&gt;
&lt;P&gt;Forced and Default modes should generally only be used for debugging or testing scenarios, where you want to ensure objects are collected at a certain point in your application, or want to compare performance data.&amp;nbsp; In future versions of the CLR, there may be new guidance for using Default, but for now, its use is discouraged.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1831076" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/clyon/archive/tags/Orcas/default.aspx">Orcas</category></item><item><title>New In Orcas Part 1: What we’ve been doing</title><link>http://blogs.msdn.com/clyon/archive/2007/03/05/new-in-orcas-part-1-what-we-ve-been-doing.aspx</link><pubDate>Tue, 06 Mar 2007 08:14:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1814520</guid><dc:creator>clyon</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/clyon/comments/1814520.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=1814520</wfw:commentRss><description>&lt;P&gt;The &lt;A class="" href="http://www.microsoft.com/downloads/details.aspx?familyid=281fcb3d-5e79-4126-b4c0-8db6332de26e&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?familyid=281fcb3d-5e79-4126-b4c0-8db6332de26e&amp;amp;displaylang=en"&gt;Orcas March CTP&lt;/A&gt;&amp;nbsp;is out, and what does that mean for the Garbage Collector?&amp;nbsp; The GC team has been concentrating on three areas for this release:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Bug fixes.&amp;nbsp; For Orcas, we’ve fixed several premature Out of Memory bugs, improved stability in certain stressful conditions, and even improved performance in some scenarios.&amp;nbsp;&amp;nbsp; &lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="" href="http://blogs.msdn.com/clyon/archive/2007/03/07/new-in-orcas-part-2-gc-collection-modes.aspx" mce_href="http://blogs.msdn.com/clyon/archive/2007/03/07/new-in-orcas-part-2-gc-collection-modes.aspx"&gt;GC Collection Modes&lt;/A&gt;.&amp;nbsp; We’ve added a new overload to System.GC.Collect that takes a System.GCCollectionMode enum, which allows the user to either force a collection or allow the GC to decide if a collection would be productive.&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="" href="http://blogs.msdn.com/clyon/archive/2007/03/12/new-in-orcas-part-3-gc-latency-modes.aspx" mce_href="http://blogs.msdn.com/clyon/archive/2007/03/12/new-in-orcas-part-3-gc-latency-modes.aspx"&gt;GC Latency Modes&lt;/A&gt;.&amp;nbsp; A new GC feature that allows the user to specify blocks of code that are time-sensitive, and the GC will minimize its intrusiveness.&amp;nbsp;&amp;nbsp; This has been implemented as new properties on the System.Runtime.GCSettings class.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;In my next few blog entries I’ll go into more detail on our new features, including code samples and best practices.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1814520" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/clyon/archive/tags/Orcas/default.aspx">Orcas</category></item><item><title>When GC.KeepAlive Doesn’t</title><link>http://blogs.msdn.com/clyon/archive/2006/08/28/728688.aspx</link><pubDate>Mon, 28 Aug 2006 21:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:728688</guid><dc:creator>clyon</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/clyon/comments/728688.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=728688</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;The purpose of GC.KeepAlive(Object) is to tell the GC not to collect an object until a certain point.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example:&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P class=MsoNormal dir=ltr style="MARGIN: 0in 0in 10pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri&gt;&lt;/FONT&gt;&lt;/o:p&gt;&lt;FONT face="Courier New" size=2&gt;class MyObject&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;~MyObject()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(“MyObject Finalized”);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal dir=ltr style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void Main()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MyObject obj = new MyObject();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LongRunningMethod();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GC.KeepAlive(obj); // ~MyObject will NOT be run before this call&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;KeepAlive will ensure ~MyObject will not get run before LongRunningMethod gets called.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is useful if the long running method passes the object out to unmanaged code, for example.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In that case, you’ll want to keep the object from being collected by the GC until the method returns.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;What’s the secret to KeepAlive?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Nothing.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It’s just a normal method with no side effects except holding a reference to an object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since it holds a reference, the JIT considers the object rooted until that point (if no other reference to this object exists and if you are not in debuggable code), and the GC will not collect it.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;So when does KeepAlive not keep an object alive?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;When it’s not called.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Ok, that was deliberately cryptic, let me illustrate using the MyObject class above:&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P class=MsoNormal dir=ltr style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face="Courier New"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;public static void Main()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;MyObject obj = new MyObject();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (true)&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GC.Collect(); // force a collection to illustrate&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;GC.KeepAlive(obj);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;BR&gt;}&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P class=MsoNormal dir=ltr style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;One would expect that when run, there would be nothing printed to the screen, since KeepAlive keeps obj from getting collected.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;But since KeepAlive is after a while(true) loop it’s actually unreachable.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Compiling the code will give you compiler warning CS0162: Unreachable code detected on the GC.KeepAlive(obj) line.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since KeepAlive is not even being called, obviously it won’t hold the object live. However if you compile the code in debug mode, the JIT will extend lifetimes of references to the end of their enclosing method.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In this case, KeepAlive actually isn’t necessary.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;But in the release case, a reference should be live until the last line of code that references it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So why is obj getting finalized?&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Looking at the IL for Main, we see what happened:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face="Courier New" size=2&gt;.method public hidebysig static void&amp;nbsp; Main() cil managed&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; .entrypoint&lt;BR&gt;&amp;nbsp; // Code size&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 21 (0x15)&lt;BR&gt;&amp;nbsp; .maxstack&amp;nbsp; 1&lt;BR&gt;&amp;nbsp; .locals init ([0] class MyObject obj,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [1] bool CS$4$0000)&lt;BR&gt;&amp;nbsp; IL_0000:&amp;nbsp; nop&lt;BR&gt;&amp;nbsp; IL_0001:&amp;nbsp; newobj&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; instance void MyObject::.ctor()&lt;BR&gt;&amp;nbsp; IL_0006:&amp;nbsp; stloc.0&lt;BR&gt;&amp;nbsp; IL_0007:&amp;nbsp; br.s&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IL_0011&lt;BR&gt;&amp;nbsp; IL_0009:&amp;nbsp; nop&lt;BR&gt;&amp;nbsp; IL_000a:&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; void [mscorlib]System.GC::Collect()&lt;BR&gt;&amp;nbsp; IL_000f:&amp;nbsp; nop&lt;BR&gt;&amp;nbsp; IL_0010:&amp;nbsp; nop&lt;BR&gt;&amp;nbsp; IL_0011:&amp;nbsp; ldc.i4.1&lt;BR&gt;&amp;nbsp; IL_0012:&amp;nbsp; stloc.1&lt;BR&gt;&amp;nbsp; IL_0013:&amp;nbsp; br.s&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IL_0009&lt;BR&gt;} // end of method MyObject::Main&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Tahoma size=2&gt;Since the code after the while loop is considered dead, the compiler has actually not built it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So the call to KeepAlive was optimized away, and is never actually called by the runtime.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The JIT then thinks it is no longer reachable after the while loop, and the GC is free to collect it.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=728688" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category></item><item><title>Object Resurrection</title><link>http://blogs.msdn.com/clyon/archive/2006/04/25/583698.aspx</link><pubDate>Wed, 26 Apr 2006 03:38:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:583698</guid><dc:creator>clyon</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/clyon/comments/583698.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=583698</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;I’m sure many of you have heard the term “object resurrection” with respect to the GC.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It’s an interesting (but not very useful) way to illustrate object lifetimes and the role of finalization versus garbage collection.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Basically, it’s a way to reference an object that has been finalized.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;FONT face=Tahoma size=2&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Here’s a rough description of how object resurrection can occur:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;FONT face=Tahoma size=2&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;OL style="MARGIN-TOP: 0in" type=1&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l0 level1 lfo1; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;A finalizable object is created.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It reachable from user code and is considered “live”.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l0 level1 lfo1; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Inside the object’s finalizer is a statement assigning the “this” pointer to a global object (like a static).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since it has a finalizer, a reference to the object is put on the finalization watchlist by the GC.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l0 level1 lfo1; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;At some point the object’s last strong reference is gone, the object is considered garbage. The object reference is then moved off the finalization watchlist and onto the freachable queue. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;Now the object is considered live again since it’s referred to by the freachable queue. and the object is considered “freachable”.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l0 level1 lfo1; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;When the finalizer thread runs the object’s finalizer, the object is removed from the freachable queue.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The global object now points to the object, making it once again reachable from user code.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The object is said to have been “resurrected” and is once again reachable from user code and considered “live”.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;FONT face=Tahoma size=2&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Here’s a code sample to illustrate:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;public class ResurrectedObj&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;~ResurrectedObj()&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;// this will resurrect the object by assigning &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: 0.5in"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;// it to the static reference&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;resurrectedReference = this;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public static ResurrectedObj resurrectedReference = null;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public static void &lt;?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /&gt;&lt;st1:place w:st="on"&gt;Main&lt;/st1:place&gt;()&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ResurrectedObj liveReference = new ResurrectedObj();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;liveReference = null;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;GC.Collect(); &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: 0.5in"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;// liveReference is now dead and the object is put on the &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: 0.5in"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;// freachable queue&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;GC.WaitForPendingFinalizers();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;// at this point, the object previously referenced &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: 0.5in"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;// by liveReference is held alive by resurrectedReference&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;FONT face=Tahoma size=2&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Unfortunately there are several implications to object resurrection which may not be immediately obvious.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For these reasons we strongly recommend against resurrecting objects.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&lt;FONT face=Tahoma size=2&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;UL style="MARGIN-TOP: 0in" type=disc&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l1 level1 lfo2; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Once the object has been resurrected, the GC has removed it from the finalization queue.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This means when the object dies again, the finalizer will not be run a second time.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To ensure the finalizer gets run, a call to GC.ReRegisterForFinalization() is required.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l1 level1 lfo2; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Attempting to use an object after the finalizer has been run, can result in undefined behavior.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Maybe the finalizer released an unmanaged resource, and you try to access it?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is the same reason why you are discouraged from accessing other managed objects from a finalizer: that object’s finalizer may have been run before yours.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l1 level1 lfo2; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;Any object referenced by your resurrected object will also be resurrected.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If any of those objects are finalizable, their finalizers may have been run, and may be in an invalid state.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-list: l1 level1 lfo2; tab-stops: list .5in"&gt;&lt;FONT face=Tahoma&gt;&lt;FONT size=2&gt;As with all finalizable objects, multiple garbage collections are required to completely clean up the object, potentially hurting performance and memory usage.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=583698" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category></item><item><title>How To Tell Which GC Mode Your Application Is Using</title><link>http://blogs.msdn.com/clyon/archive/2005/02/04/367419.aspx</link><pubDate>Fri, 04 Feb 2005 22:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:367419</guid><dc:creator>clyon</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/clyon/comments/367419.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=367419</wfw:commentRss><description>&lt;p&gt;I posted &lt;a href="http://weblogs.asp.net/clyon/archive/2004/09/08/226981.aspx"&gt;previously &lt;/a&gt;about how to set the GC mode your application.&amp;nbsp; So now that you’re running your app, how do you know it’s running in that GC mode?&lt;/p&gt; &lt;p&gt;If you’re using v1.0 or v1.1, the CLR loads a different dll based on which GC mode (mscorwks.dll for workstation, mscorsvr.dll for server).&amp;nbsp; You can use tasklist.exe (ships with Windows XP and up) or tlist.exe (ships with &lt;a href="http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx"&gt;Windows Debugging Tools&lt;/a&gt;) to determine which processes are using which dll.&amp;nbsp; To list all the applications running with server GC:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;tasklist /m mscorsvr.dll&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;or&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;tlist /m mscorsvr.dll&lt;/p&gt; &lt;p&gt;In Whidbey, we’ve condensed all the GC code into one library: mscorwks.dll.&amp;nbsp; This means that all managed applications load mscorwks.dll, making the old method useless.&amp;nbsp; Luckily we have two new ways to determine the GC mode:&lt;/p&gt; &lt;p&gt;System.Runtime.GCSettings.IsServerGC will return true if we’re in server GC mode, and false if in workstation.&amp;nbsp; Note, this API is in a &lt;A href="http://blogs.msdn.com/junfeng/archive/2004/07/13/181534.aspx"&gt;different location&lt;/a&gt; from Whidbey Beta 1. &lt;/p&gt; &lt;p&gt;The other way is using SOS, the debugger extension to WinDBG and Visual Studio.&amp;nbsp; When your assembly is running, you can query the GC mode with:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!EEVersion&lt;/p&gt; &lt;p&gt;One thing to note is that this will only return the GC mode and the number of heaps after the heap (or heaps) has been initialized.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=367419" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/clyon/archive/tags/Server+GC/default.aspx">Server GC</category></item><item><title>To Null or Not to Null</title><link>http://blogs.msdn.com/clyon/archive/2004/12/01/273144.aspx</link><pubDate>Wed, 01 Dec 2004 18:23:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:273144</guid><dc:creator>clyon</dc:creator><slash:comments>13</slash:comments><comments>http://blogs.msdn.com/clyon/comments/273144.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=273144</wfw:commentRss><description>&lt;p&gt;GC Myth: setting an object's reference to null will force the GC to collect it right away.&lt;br /&gt;GC Truth: setting an object's reference to null will sometimes allow the GC to collect it sooner. &lt;/p&gt; &lt;p&gt;As much as you may want to, you can't guarantee the GC will collect what you want, when you want it to. The best you can do is give it hints. The GC typically does collections when an allocation fails, not necessarily as soon as you're done with an object. &lt;/p&gt; &lt;p&gt;Consider the following method. What is the earliest point the GC could collect the Object that obj references? &lt;/p&gt; &lt;p class="code"&gt;void Foo() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object obj = new Object();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(obj.ToString());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i=0; i&amp;lt;10; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(i);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;obj = null;&lt;br /&gt;} &lt;/p&gt; &lt;p&gt;The answer depends on whether you've compiled it in Debug or Release mode. In Debug, the JIT extends all references' lifetimes to the end of their scope. This is so you don't have to worry about the GC cleaning up a variable you're trying to inspect! &lt;/p&gt; &lt;p&gt;In Release mode, the Object is actually first eligible for collection after the call to ToString(). The JIT is usually smart enough to realize that obj = null can be optimized away. That leaves obj.ToString() as the last reference to the object. So after the call to ToString(), the obj is no longer used and is removed as a GC Root. That leaves the Object in memory orphaned (no references pointing to it), making it eligible for collection. When the GC actually goes about collecting it, is another matter. &lt;/p&gt; &lt;p&gt;So when does setting a reference to null allow the object in memory to be reclaimed sooner? &lt;/p&gt;Consider instance variables. Imagine a class that contains a large array of a managed type. There could be times where you no longer need that array, but you want the object to hang around. This is a good case for the Dispose pattern: &lt;p&gt;&lt;/p&gt; &lt;p class="code"&gt;class BigObject : IDisposable {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int[,] array = new int[1024,1024];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void Dispose() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;array = null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;} &lt;/p&gt; &lt;p&gt;Now the GC will clean up the array when it does its next collection, and you can keep that BigObject around for whatever reason, and not worry about it taking up so much memory. &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=273144" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category></item><item><title>Part 2 in Maoni's Using GC Efficiently</title><link>http://blogs.msdn.com/clyon/archive/2004/09/27/234975.aspx</link><pubDate>Mon, 27 Sep 2004 23:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:234975</guid><dc:creator>clyon</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/clyon/comments/234975.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=234975</wfw:commentRss><description>&lt;p&gt; &lt;a href="http://blogs.msdn.com/maoni"&gt;Maoni&lt;/a&gt; posted &lt;a href="http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx"&gt;Part 2&lt;/a&gt; to Using the GC Efficiently.&amp;nbsp; A very in-depth article about Server, Workstation and Concurrent GC.&amp;nbsp; Check it out. &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=234975" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category></item><item><title>GCHandles, Boxing and Heap Corruption</title><link>http://blogs.msdn.com/clyon/archive/2004/09/17/230985.aspx</link><pubDate>Fri, 17 Sep 2004 18:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:230985</guid><dc:creator>clyon</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/clyon/comments/230985.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=230985</wfw:commentRss><description>&lt;p&gt;A GCHandle is a struct used to hold onto a managed object to be used by unmanaged code.&amp;nbsp; With a GCHandle you can (among other things): &lt;ul&gt; &lt;li&gt;Prevent an object from being garbage collected if unmanaged code has the only live reference to it &lt;li&gt;Pin an object in memory, so it won’t be relocated in memory by the garbage collector &lt;li&gt;Get the memory address of the pinned object&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The last point is interesting.&amp;nbsp; When dealing with managed code, addresses of reference objects (objects allocated on the heap) are not constant.&amp;nbsp; As the GC tries to reclaim memory, it moves objects around in memory and compacts the heap.&amp;nbsp; If you’re P/Invoking into an unmanaged DLL, you may need to pass the address of some object.&amp;nbsp; That’s where GCHandles come in.&lt;/p&gt; &lt;p&gt;The syntax for allocating a pinned GCHandle is as follows (C# code):&lt;/p&gt; &lt;div class="code"&gt;Int[] arr = new int[10];&lt;br /&gt;GCHandle gch = GCHandle.Alloc(arr, GCHandleType.Pinned);&lt;/div&gt; &lt;p&gt;The above code pins arr in memory (so it won’t be moved), and creates a new GCHandle that “wraps” arr.&amp;nbsp; You can now get the address of arr using GCHandle.AddrOfPinnedObject.&lt;/p&gt; &lt;p class="aside"&gt;Note: you can only pin blittable types in memory (types that have the same representation in managed and unmanaged code).&amp;nbsp; Blittable types include primitive types and arrays.&lt;/p&gt; &lt;p&gt;The problem occurs when you accidentally misuse Alloc.&amp;nbsp; For example, I’ve seen code like this:&lt;/p&gt; &lt;div class="code"&gt;Object obj = new Object();&lt;br /&gt;GCHandle gch2 = GCHandle.Alloc(Marshal.SizeOf(typeof(obj)), GCHandleType.Pinned);&lt;/div&gt; &lt;p&gt;It looks like the developer tried to allocate a GCHandle with the same size as obj in memory.&amp;nbsp; So what does this code actually do?&lt;/p&gt; &lt;p&gt;Marshall.SizeOf returns an int that when passed to a method expecting an Object, is boxed into a newly heap-allocated Object.&amp;nbsp; So the new GCHandle obediently pins this new Object in memory.&amp;nbsp; Then when you pass gch2.AddrOfPinnedObject to your unmanaged code… trouble.&lt;/p&gt; &lt;p&gt;Consider an unmanaged method takes an array of ints, and increments each element.&amp;nbsp; You’ve passed it an address, and it dutifully increments each value it finds for the length of the array.&amp;nbsp; Congratulations, you’ve just corrupted memory.&lt;/p&gt; &lt;p&gt;If you’re lucky, this crashes the runtime right away.&amp;nbsp; If you’re unlucky, your app may continue to run and crash sometime in the future or your app’s data may be messed up.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=230985" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/clyon/archive/tags/GCHandles/default.aspx">GCHandles</category></item><item><title>A Few Good GC Links</title><link>http://blogs.msdn.com/clyon/archive/2004/09/14/229477.aspx</link><pubDate>Tue, 14 Sep 2004 17:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:229477</guid><dc:creator>clyon</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/clyon/comments/229477.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=229477</wfw:commentRss><description>&lt;p&gt;I keep a GC folder in my Favorites full of links to articles and blog posts about the .NET GC.&amp;nbsp; I thought it would be a good idea to consolidate them all into one blog post, for handy reference.&amp;nbsp; These are the articles I most often post as answers to questions on public newsgroups.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;If you know of any other good ones, please post them in the comments!&amp;nbsp; If you find some totally erroneous articles, point them out too.&lt;/p&gt; &lt;p&gt;GC Overview and Best Practices:&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/msdnmag/issues/1100/gci/"&gt;http://msdn.microsoft.com/msdnmag/issues/1100/gci/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/default.aspx"&gt;http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/default.aspx&lt;/a&gt;&lt;br /&gt;Garbage Collection (parts 1 &amp;amp; 2): Automatic Memory Management in the Microsoft .NET Framework &lt;br /&gt;Jeffrey Richter&lt;/p&gt; &lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconfinalizedispose.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconfinalizedispose.asp&lt;/a&gt;&lt;br /&gt;Implementing Finalize and Dispose to Clean Up Unmanaged Resources&lt;br /&gt;.NET Framework General Reference&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx"&gt;http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx&lt;/a&gt;&lt;br /&gt;Finalization&lt;br /&gt;Chris Brumme&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/cbrumme/archive/2003/04/15/51319.aspx"&gt;http://blogs.msdn.com/cbrumme/archive/2003/04/15/51319.aspx&lt;/a&gt;&lt;br /&gt;Turning off the garbage collector&lt;br /&gt;Chris Brumme&lt;/p&gt; &lt;p&gt;Performance:&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetGCbasics.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetGCbasics.asp&lt;/a&gt;&lt;br /&gt;Garbage Collector Basics and Performance Hints&lt;br /&gt;Rico Mariani&lt;/p&gt; &lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp&lt;/a&gt;&lt;br /&gt;Improving .NET Application Performance and Scalability: Chapter 5 — Improving Managed Code Performance&lt;br /&gt;J.D. Meier, Srinath Vasireddy, Ashish Babbar, Rico Mariani, and Alex Mackman&lt;/p&gt; &lt;p&gt;&lt;A href="http://weblogs.asp.net/ricom/archive/2003/12/04/41281.aspx"&gt;http://weblogs.asp.net/ricom/archive/2003/12/04/41281.aspx&lt;/a&gt;&lt;br /&gt;Mid-life crisis&lt;br /&gt;Rico Mariani&lt;/p&gt; &lt;p&gt;&lt;A href="http://weblogs.asp.net/ricom/archive/2003/12/02/40780.aspx"&gt;http://weblogs.asp.net/ricom/archive/2003/12/02/40780.aspx&lt;/a&gt;&lt;br /&gt;Two things to avoid for better memory usage&lt;br /&gt;Rico Mariani&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/maoni/archive/2004/06/15/156626.aspx"&gt;http://blogs.msdn.com/maoni/archive/2004/06/15/156626.aspx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx"&gt;http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx&lt;/a&gt;&lt;br /&gt;Using GC Efficiently - Parts 1 &amp;amp; 2&lt;br /&gt;Maoni Stephens&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Added link to Maoni's GC posts.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=229477" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category></item><item><title>Server GC Misconceptions</title><link>http://blogs.msdn.com/clyon/archive/2004/09/10/228104.aspx</link><pubDate>Fri, 10 Sep 2004 23:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:228104</guid><dc:creator>clyon</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/clyon/comments/228104.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=228104</wfw:commentRss><description>&lt;p&gt;One of the most common “bugs” I read about on the Microsoft public newsgoups is the fact that the runtime does not automatically choose Server GC mode on a multi-proc machine, or server OS. &lt;/p&gt; &lt;p&gt;If the server OS is running on a single-proc machine then the runtime will have to load the Workstation GC, since Server GC doesn’t work on a single proc, so we’re down to just the multi-proc issue. &lt;/p&gt; &lt;p&gt;Let’s imagine for a minute that the runtime did choose Server GC on its own. &lt;/p&gt; &lt;p&gt;If Server GC is automatically enabled, then all applications, both applications running as services and user applications will use this GC mode. This is good news for the services, but bad news for the user applications. &lt;/p&gt; &lt;p&gt;Like I explained in &lt;A href="http://blogs.msdn.com/clyon/archive/2004/09/08/226981.aspx"&gt;my previous post&lt;/a&gt;, user applications are best run with Concurrent GC, to maximize responsiveness. Unfortunately, Server GC and Concurrent GC are incompatible, so the runtime has effectively made user applications perform worse on a multi-proc machine than they do on a single proc! And since there’s no way to specify which GC mode to use (in v1.0 and v1.1 pre-SP1), you’re stuck with services with optimized throughput, and laggy user interfaces. This really sucks if you happen to have bought a brand new machine with a Hyperthreaded processor, and want to run managed apps on it! &lt;/p&gt; &lt;p&gt;The CLR Team decided on behaviour with the least negative performance impact, so you either have to host your service if you want it run with Server GC, or use config files.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=228104" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/clyon/archive/tags/Server+GC/default.aspx">Server GC</category></item><item><title>Server, Workstation and Concurrent GC</title><link>http://blogs.msdn.com/clyon/archive/2004/09/08/226981.aspx</link><pubDate>Wed, 08 Sep 2004 18:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:226981</guid><dc:creator>clyon</dc:creator><slash:comments>28</slash:comments><comments>http://blogs.msdn.com/clyon/comments/226981.aspx</comments><wfw:commentRss>http://blogs.msdn.com/clyon/commentrss.aspx?PostID=226981</wfw:commentRss><description>&lt;p&gt;One common question I see asked is the differences between server and workstation GC, and how Concurrent GC fits in. &lt;/p&gt; &lt;p&gt;Server GC is only available on multi-proc machines. It creates one GC heap (and thus one GC thread) for each processor, which are collected in parallel. This GC mode maximizes throughput (number of requests per second) and shows good scalability (performance really shines with 4 or more processors). &lt;/p&gt; &lt;p&gt;Workstation is the default GC mode. On a single-proc machine, it’s the only option.&lt;/p&gt; &lt;p&gt;Concurrent GC is used in Workstation mode on a multi-proc machine. It performs full collections (generation 2) concurrently with the running program, minimizing the pause time. This mode is particularly useful for applications with graphical user interfaces or applications where responsiveness is essential. &lt;/p&gt; &lt;p&gt;How do I choose a GC mode?&lt;/p&gt; &lt;p&gt;In v1.0 and v1.1 (pre-SP1), server mode can only be used if the runtime is hosted in an unmanaged application (for example, ASP.NET hosts web applications in server mode). Concurrent mode can be specified in the machine or application’s configuration file. If neither is chosen, or if on a single-proc machine, Workstation is the default.&lt;/p&gt; &lt;p class="aside"&gt;Note: Server mode automatically disables Concurrent GC.&lt;/p&gt; &lt;p&gt;To set GC mode to Concurrent:&lt;/p&gt; &lt;div class="code"&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;runtime&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;gcConcurrent enabled="true" /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/runtime&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt; &lt;/div&gt; &lt;p&gt;To set GC mode to Server (unmanaged C++): &lt;div class="code"&gt;HRESULT CorBindToRuntimeEx( LPWSTR pwszVersion,&lt;br /&gt;&amp;nbsp;&amp;nbsp;LPWSTR pwszBuildFlavor, // use “svr” for server mode,&lt;br /&gt;&amp;nbsp;&amp;nbsp;// “wks” or NULL for workstation&lt;br /&gt;&amp;nbsp;&amp;nbsp;DWORD flags,&lt;br /&gt;&amp;nbsp;&amp;nbsp;REFCLSID rclsid,&lt;br /&gt;&amp;nbsp;&amp;nbsp;REFIID riid,&lt;br /&gt;&amp;nbsp;&amp;nbsp;LPVOID* ppv ); &lt;/div&gt; &lt;p&gt;One of the most popular feature requests was the ability to specify the GC mode in a non-hosted managed application. In Whidbey (v2.0) and v1.1 SP1, we added a new feature that allows you to specify the GC mode in the application’s config file:&lt;/p&gt; &lt;div class="code"&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;runtime&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;gcServer enabled="true" /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/runtime&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt; &lt;/div&gt; &lt;p class="aside"&gt;Note: if the application is hosted, the host’s GC mode overrides the config file.&lt;/p&gt; &lt;p&gt;How do I tell which GC mode my app is using?&lt;/p&gt; &lt;p&gt;In v1.0 and v1.1 of the CLR, the GC was contained in two core DLLs: mscorwks.dll and mscorsvr.dll. If the application is running in server mode, then mscorsvr.dll is loaded, otherwise, mscorwks.dll is loaded. The only way to tell which is loaded is to look at the list of running processes.&lt;/p&gt; &lt;p&gt;Remember, on a single proc-machine, it’s Workstation. On a multi-proc where throughput is important, use Server. If there's user interaction, choose Concurrent.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Minor corrections.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Fixed case in XML tags. Thanks Tyler!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=226981" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/clyon/archive/tags/GC/default.aspx">GC</category><category domain="http://blogs.msdn.com/clyon/archive/tags/Server+GC/default.aspx">Server GC</category></item></channel></rss>