<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">Yun Jin's WebLog</title><subtitle type="html">CLR internals, Rotor code explanation, CLR debugging tips, trivial debugging notes, .NET programming pitfalls, and blah, blah, blah...</subtitle><id>http://blogs.msdn.com/yunjin/atom.xml</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/yunjin/atom.xml" /><generator uri="http://communityserver.org" version="2.1.61025.2">Community Server</generator><updated>2004-01-27T20:52:00Z</updated><entry><title>Trivial debugging note - using WeakReference in finalizer</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/08/31/458231.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/08/31/458231.aspx</id><published>2005-08-31T19:42:00Z</published><updated>2005-08-31T19:42:00Z</updated><content type="html">&lt;P&gt;Some time ago I saw a problem from a partner team in Microsoft that an &lt;EM&gt;InvalidOperationException&lt;/EM&gt; is thrown from &lt;EM&gt;WeakReference.IsAlive&lt;/EM&gt;. &lt;EM&gt;WeakReference&lt;/EM&gt; wraps weak &lt;EM&gt;GC handle&lt;/EM&gt; implemented in CLR's &lt;EM&gt;Execution Engine&lt;/EM&gt; (&lt;EM&gt;GC handle&amp;nbsp;&lt;/EM&gt;is also exposed by &lt;EM&gt;System.Runtime.InteropServices.GCHandle &lt;/EM&gt;which supports&amp;nbsp;not only weak&amp;nbsp;&lt;EM&gt;handles, &lt;/EM&gt;but other types too&lt;EM&gt;)&lt;/EM&gt;. A weak &lt;EM&gt;GC handle&lt;/EM&gt; will be allocated and assigned to the &lt;EM&gt;WeakReference&lt;/EM&gt; object when the &lt;EM&gt;WeakReference&lt;/EM&gt; object is created. As described by &lt;A href="http://www.msdn.microsoft.com/msdnmag/issues/1200/GCI2/default.aspx"&gt;Jeffrey Richiter&lt;/A&gt;, the weak &lt;EM&gt;GC handle&lt;/EM&gt; contains pointer to an object, if the object is collected by GC, the &lt;EM&gt;GC handle&lt;/EM&gt; will be cleared to NULL. Most of time &lt;EM&gt;WeakReference.IsAlive &lt;/EM&gt;returns &lt;EM&gt;true&lt;/EM&gt; or &lt;EM&gt;false&lt;/EM&gt; to indicate whether the tracked object is alive. The check is based on whether the underlying &lt;EM&gt;GC handle&lt;/EM&gt; contains a non-NULL pointer or NULL. Similarly, &lt;EM&gt;WeakReference.get_Target&lt;/EM&gt; will return a valid object reference or &lt;EM&gt;null&lt;/EM&gt;. But after the &lt;EM&gt;WeakReference&lt;/EM&gt; object itself becomes unrooted and finalized, the underlying &lt;EM&gt;GC handle&lt;/EM&gt; will be destroyed and any call to &lt;EM&gt;IsAlive&lt;/EM&gt; or &lt;EM&gt;get_Target&lt;/EM&gt; on the &lt;EM&gt;WeakReference&lt;/EM&gt; object will throw &lt;EM&gt;InvalidOperationException&lt;/EM&gt; in V1.X.&lt;/P&gt;
&lt;P&gt;How would any method being called on a finalized object? Well, if one object &lt;EM&gt;O&lt;/EM&gt; has a field &lt;EM&gt;WR&lt;/EM&gt; as &lt;EM&gt;WeakReference&lt;/EM&gt;, when &lt;EM&gt;O&lt;/EM&gt; become unrooted and there are no other roots&amp;nbsp;for &lt;EM&gt;WR&lt;/EM&gt;, both objects are considered to be dead and will be put into F-reachable queue for finalization(check also check &lt;A href="http://www.msdn.microsoft.com/msdnmag/issues/1100/GCI/default.aspx"&gt;Jeffrey's article&lt;/A&gt;). Since there are no guarantee about order of finalizers (things are a little bit different for critical finalizer),&amp;nbsp;when &lt;EM&gt;O&lt;/EM&gt;'s finalizer is executed, &lt;EM&gt;WR&lt;/EM&gt; may already be finalized. Thus inside &lt;EM&gt;O&lt;/EM&gt;'s finalizer or after &lt;EM&gt;O&lt;/EM&gt; is resurrected, it could call methods on the finalized &lt;EM&gt;WR&lt;/EM&gt;. In the example I mentioned at the beginning, the problem is some object's finalizer is calling &lt;EM&gt;IsAlive&lt;/EM&gt; on its &lt;EM&gt;WeakReference &lt;/EM&gt;field.&lt;/P&gt;
&lt;P&gt;The guideline for finalization says not to use any finalizable field in finalizer, so it's fair for &lt;EM&gt;WeakReference&lt;/EM&gt;'s properties to throw exception if they are called in finalizer. But it might be hard for people to understand why &lt;EM&gt;IsAlive&lt;/EM&gt; needs to throw. After all it's only used to check status and doesn't&amp;nbsp;need to access the tracked object if it's already collected. I think the reasoning is that &lt;EM&gt;IsAlive&lt;/EM&gt; is meant to check whether the underlying &lt;EM&gt;GC handle &lt;/EM&gt;tracks a live object, but if the &lt;EM&gt;GC handle &lt;/EM&gt;is already gone during &lt;EM&gt;WeakReference&lt;/EM&gt;'s finalization, we can't answer the question.&lt;/P&gt;
&lt;P&gt;The most interesting part is to look at history of this design decision. In V1.X, both &lt;EM&gt;IsAlive &lt;/EM&gt;and &lt;EM&gt;get_Target &lt;/EM&gt;property throws exception after the &lt;EM&gt;WeakRerence &lt;/EM&gt;object is finalized; in Beta2 of V2.0, &lt;EM&gt;IsAlive&lt;/EM&gt; still throws, but &lt;EM&gt;get_Target &lt;/EM&gt;won't throw, it will return &lt;EM&gt;null &lt;/EM&gt;after finalization; after Beta2, we made a change so that &lt;EM&gt;IsAlive &lt;/EM&gt;won't throw either, it will return false after finalization. Partly because there are too many people calling &lt;EM&gt;WeakReference.IsAlive &lt;/EM&gt;in finalizers, and it is not a really dangerous thing to do. Note that &lt;EM&gt;WeakReference.set_Target &lt;/EM&gt;always throws after finalization.&lt;/P&gt;
&lt;P&gt;So&amp;nbsp;on CLR V2.0 offical released build, you could safely use &lt;EM&gt;WeakReference &lt;/EM&gt;in finalizer.But&amp;nbsp;it is still good practice not to use&amp;nbsp;finalizable objects in finalizer, including &lt;EM&gt;WeakReference&lt;/EM&gt;.&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=458231" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /></entry><entry><title>Thread, System.Threading.Thread, and !Threads (III)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/08/30/457756.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/08/30/457756.aspx</id><published>2005-08-30T19:55:00Z</published><updated>2005-08-30T19:55:00Z</updated><content type="html">&lt;P&gt;I got email asking me to explain &lt;EM&gt;!Threads&lt;/EM&gt; output in details. I think this is a good question and a good topic for another installment to the series.&lt;/P&gt;
&lt;P&gt;Here is an example I'll use for this post:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:055&amp;gt; !threads&lt;BR&gt;ThreadCount: 202&lt;BR&gt;UnstartedThread: 95&lt;BR&gt;BackgroundThread: 1&lt;BR&gt;PendingThread: 0&lt;BR&gt;DeadThread: 47&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;&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;&amp;nbsp; PreEmptive&amp;nbsp;&amp;nbsp; GC Alloc&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Lock&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ID&amp;nbsp; ThreadOBJ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; State&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Context&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Domain&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Count APT Exception&lt;BR&gt;&amp;nbsp; 0&amp;nbsp; 0xed0 0x0014f260&amp;nbsp;&amp;nbsp; 0x2000020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 Ukn&lt;BR&gt;&amp;nbsp; 1&amp;nbsp; 0xa3c 0x00157d28&amp;nbsp;&amp;nbsp; 0x2001220 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn (Finalizer)&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00166378&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp; 4 0x12cc 0x00166540&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 STA&lt;BR&gt;&amp;nbsp; 5 0x12dc 0x00166708&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp; 3&amp;nbsp; 0xe7c 0x00175b70&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00175d38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00175f00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x001760c8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00176290&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn System.InvalidOperationException&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00176458&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00176620&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x001767e8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;12&amp;nbsp; 0x7e0 0x001769b0&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;13 0x15e8 0x00178008&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;14&amp;nbsp; 0x4d0 0x001781d0&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00178398&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00178560&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00178728&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x001788f0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00178ab8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00178c80&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00178e48&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;21 0x14f0 0x00179010&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;22 0x1708 0x001791d8&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;23 0x11f8 0x001793a0&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;24&amp;nbsp; 0x224 0x00179568&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00179730&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x001798f8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00179ac0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn System.InvalidOperationException&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00179c88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn System.InvalidOperationException&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00179e50&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149aa0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;...&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;First &lt;EM&gt;!Threads&lt;/EM&gt; gives some statistics about &lt;EM&gt;Thread Store&lt;/EM&gt;.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;ThreadCount&lt;/EM&gt;: number of total &lt;EM&gt;C++ Thread&lt;/EM&gt; objects in &lt;EM&gt;Thread Store&lt;/EM&gt;.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;UnstartedThread&lt;/EM&gt;: number of &lt;EM&gt;C++ Thread&lt;/EM&gt; objects marked as unstarted. Recall I mentioned in &lt;A href="http://http://blogs.msdn.com/yunjin/archive/2005/08/25/456355.aspx"&gt;previous blog&lt;/A&gt;, if a user creates a &lt;EM&gt;C# Thread&lt;/EM&gt; object, CLR will create an "unstarted" &lt;EM&gt;C++ Thread&lt;/EM&gt; object. When &lt;EM&gt;Thread.Start&lt;/EM&gt; is called on the C# object, CLR will create an &lt;EM&gt;OS thread&lt;/EM&gt; and remove "unstarted" flag from the &lt;EM&gt;C++ Thread&lt;/EM&gt; object.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;BackgroundThread&lt;/EM&gt;: number of &lt;EM&gt;C++ Threads&lt;/EM&gt; (and the corresponding &lt;EM&gt;OS threads&lt;/EM&gt;) considered as background. Being background simply means CLR won't wait the thread for shutting down. Threads created explicitly by using &lt;EM&gt;System.Threading.Thread.Start&lt;/EM&gt; are by default foreground threads; whereas threads wandering into CLR from unmanaged world are by default background threads (Rotor: &lt;EM&gt;SetupThread&lt;/EM&gt; in&lt;EM&gt; vm/threads.cpp&lt;/EM&gt; calls &lt;EM&gt;SetBackground(TRUE)&lt;/EM&gt;). However, whether a thread is background could be changed by using&amp;nbsp;&lt;EM&gt;IsBackground&lt;/EM&gt; property in &lt;EM&gt;C# Thread&lt;/EM&gt; object.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;PendingThreads&lt;/EM&gt;: If an &lt;EM&gt;OS thread&lt;/EM&gt; is created but its &lt;EM&gt;ThreadProc&lt;/EM&gt; hasn't be executed to the place to decrement unstarted counter in &lt;EM&gt;Thread Store&lt;/EM&gt;, the thread is considered&amp;nbsp;to be pending. Number of this type of threads should be quite low.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;DeadThreads&lt;/EM&gt;: Number of &lt;EM&gt;C++ Thread&lt;/EM&gt; objects whose &lt;EM&gt;OS threads&lt;/EM&gt; are already dead but the &lt;EM&gt;C++ objects&lt;/EM&gt; themselves are not deleted yet.&lt;/P&gt;
&lt;P&gt;In Rotor, all the five numbers are actually stored in &lt;EM&gt;ThreadStore (vm/threads.h)&lt;/EM&gt; object as its fields.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Then it comes a table of all &lt;EM&gt;C++ Thread&lt;/EM&gt; objects in Thread Store. Let me explain each field.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The first column doesn't have a header. It is the &lt;EM&gt;OS thread&lt;/EM&gt; ID given by debugger just for debugging readability. Because the numbers only exist in debugger process, not the debuggee process, you may see the number being different when you look at a live session than when you debug a dump taken from the same live session. For a "dead"&amp;nbsp;or "unstarted" thread, this column is "XXX".&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;ID&lt;/EM&gt;: this is the thread ID assigned by OS, it remains consistent during debugger sessions, but OS could recycle it.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;ThreadOBJ&lt;/EM&gt;: address of &lt;EM&gt;C++ Thread&lt;/EM&gt; object. You could see contents of the object by &lt;EM&gt;"dt mscorwks!Thread &amp;lt;address&amp;gt;"&lt;/EM&gt; if you have symbols for mscorwks.dll.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;State&lt;/EM&gt;: one of the most important fields of the table. For Rotor, it is the &lt;EM&gt;C++ Thread's m_State&lt;/EM&gt; field.&amp;nbsp; It is combination of&amp;nbsp;bit masks&amp;nbsp;to indicate what the status the &lt;EM&gt;Thread&lt;/EM&gt; currently is. All possible states (bit masks)&amp;nbsp;are defined as enum &lt;EM&gt;ThreadState&lt;/EM&gt; in &lt;EM&gt;vm/Threads&lt;/EM&gt;. We already covered several states like &lt;EM&gt;TS_Background&lt;/EM&gt;, &lt;EM&gt;TS_Unstarted&lt;/EM&gt;, and &lt;EM&gt;TS_Dead&lt;/EM&gt;. More states include &lt;EM&gt;TS_AbortRequested&lt;/EM&gt; (this thread is requested to be aborted), &lt;EM&gt;TS_AbortInitiated&lt;/EM&gt; (abort process is already started for this thread), &lt;EM&gt;TS_GCSuspendPending&lt;/EM&gt; (GC is trying to suspend this thread), and etc.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Preemptive GC&lt;/EM&gt;: also very important. In Rotor, this is &lt;EM&gt;m_fPreemptiveGCDisabled&lt;/EM&gt; field of&lt;EM&gt; C++ Thread&lt;/EM&gt; class. It indicates what GC mode the thread is in: "enabled" in the table means the thread is in &lt;EM&gt;preemptive mode&lt;/EM&gt; where GC could preempt this thread at any time; "disabled" means the thread is in cooperative mode where GC has to wait the thread to give up its current work (the work is related to GC objects so it can't allow GC to move the objects around). When the thread is executing managed code (the current IP is in managed code), it is always in cooperative mode; when the thread is in &lt;EM&gt;Execution Engine&lt;/EM&gt; (unmanaged code), &lt;EM&gt;EE &lt;/EM&gt;code could choose to stay in either mode and could switch mode at any time; when a thread are outside of CLR (e.g, calling into native code using interop), it is always in preemptive mode.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;GC Alloc context&lt;/EM&gt;: allocate context GC might use when it tries to allocate object for this thread. In Rotor, it is &lt;EM&gt;m_alloc_context&lt;/EM&gt; in &lt;EM&gt;C++ Thread&lt;/EM&gt; object. &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Domain&lt;/EM&gt;: which &lt;EM&gt;AppDomain&lt;/EM&gt; the thread is currently in (Rotor:&lt;EM&gt; m_pDomain&lt;/EM&gt; field of &lt;EM&gt;C++ Thread&lt;/EM&gt; class). You could use &lt;EM&gt;!DumpDomain&lt;/EM&gt; or "dt mscorwks!AppDomain" to dump details of the domain. A thread can only be in one domain at a time, but it could switch into different domains. Speical marks will be put on thread's stack to when it transit to another domain.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Lock count&lt;/EM&gt;: how many locks this thread has taken (Rotor: &lt;EM&gt;m_dwLockCount&lt;/EM&gt; field of &lt;EM&gt;C++ Thread&lt;/EM&gt; class). The locks it tracks include the managed monitors (taken by &lt;EM&gt;lock(obj)&lt;/EM&gt; in C#),&amp;nbsp;BCL's &lt;EM&gt;ReaderWriterLock&lt;/EM&gt;, and certain locks inside CLR's unmanaged code.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;APT&lt;/EM&gt;: &lt;EM&gt;COM&lt;/EM&gt; apartment for the thread, whether the thread is in a single-threaded apartment (&lt;EM&gt;STA&lt;/EM&gt;), multithreaded apartment(&lt;EM&gt;MTA&lt;/EM&gt;) or unknown.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Exception&lt;/EM&gt;: the last managed exception thrown from this thread. It is saved in a GC handle in the &lt;EM&gt;C++ Thread&lt;/EM&gt; object (Rotor: &lt;EM&gt;m_LastThrownObjectHandle&lt;/EM&gt;).&lt;/P&gt;
&lt;P&gt;The last column also indicates which &lt;a href="http://blogs.msdn.com/yunjin/archive/2005/07/05/435726.aspx"&gt;special thread &lt;/A&gt;this thread is. However,&amp;nbsp;&lt;EM&gt;!Threads&lt;/EM&gt; only recognize&amp;nbsp;a limited type of special threads for this field, including &lt;EM&gt;Finalizer thread&lt;/EM&gt;, &lt;EM&gt;GC thread&lt;/EM&gt;, &lt;EM&gt;Threadpool Worker thread&lt;/EM&gt;, and &lt;EM&gt;Threadpool Completion Port thread&lt;/EM&gt;. And for special threads which doesn't have a &lt;EM&gt;C++ Thread &lt;/EM&gt;object (a special thread doesn't need to run managed code like debugger helper thread and server GC thread), they&amp;nbsp;can not be displayed here. In Whidbey, a "&lt;EM&gt;-special&lt;/EM&gt;" option is added to &lt;EM&gt;!Threads &lt;/EM&gt;command which will show all special threads in the process as a separate list. Here is a sample output:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:007&amp;gt; !threads -special&lt;BR&gt;ThreadCount: 4&lt;BR&gt;UnstartedThread: 0&lt;BR&gt;BackgroundThread: 3&lt;BR&gt;PendingThread: 0&lt;BR&gt;DeadThread: 0&lt;BR&gt;Hosted Runtime: no&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;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PreEmptive&amp;nbsp;&amp;nbsp; GC Alloc&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Lock&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ID OSID ThreadOBJ&amp;nbsp;&amp;nbsp;&amp;nbsp; State&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Context&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Domain&amp;nbsp;&amp;nbsp; Count APT Exception&lt;BR&gt;&amp;nbsp;&amp;nbsp; 0&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp; 828 0029a030&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a020 Disabled 06907c38:069081d4 0f59e038&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 MTA&lt;BR&gt;&amp;nbsp;&amp;nbsp; 4&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 16fc 0029e980&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; b220 Enabled&amp;nbsp; 0690424c:069061d4 0021f4a8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 MTA (Finalizer)&lt;BR&gt;&amp;nbsp;&amp;nbsp; 5&amp;nbsp;&amp;nbsp;&amp;nbsp; 3 1c1c 002e71e8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1220 Enabled&amp;nbsp; 028f20f8:028f3f94 0021f4a8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;&amp;nbsp; 6&amp;nbsp;&amp;nbsp;&amp;nbsp; 4 1244 0f6fa778&amp;nbsp;&amp;nbsp;&amp;nbsp; 80a220 Enabled&amp;nbsp; 00000000:00000000 0021f4a8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 MTA (Threadpool Completion Port)&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OSID&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Special thread type&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp; e20&amp;nbsp;&amp;nbsp;&amp;nbsp; DbgHelper &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2&amp;nbsp;&amp;nbsp; 1e1c&amp;nbsp;&amp;nbsp;&amp;nbsp; GC &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3&amp;nbsp;&amp;nbsp; 1ed4&amp;nbsp;&amp;nbsp;&amp;nbsp; GC &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4&amp;nbsp;&amp;nbsp; 16fc&amp;nbsp;&amp;nbsp;&amp;nbsp; Finalizer &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5&amp;nbsp;&amp;nbsp; 1c1c&amp;nbsp;&amp;nbsp;&amp;nbsp; ADUnloadHelper &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6&amp;nbsp;&amp;nbsp; 1244&amp;nbsp;&amp;nbsp;&amp;nbsp; Timer&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=457756" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="Rotor code explanation" scheme="http://blogs.msdn.com/yunjin/archive/tags/Rotor+code+explanation/default.aspx" /><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>Thread, System.Threading.Thread, and !Threads (II)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/08/29/457150.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/08/29/457150.aspx</id><published>2005-08-29T19:30:00Z</published><updated>2005-08-29T19:30:00Z</updated><content type="html">&lt;P&gt;With knowledge in my &lt;A href="https://blogs.msdn.com/yunjin/archive/2005/08/25/456355.aspx"&gt;previous blog&lt;/A&gt;, we could avoid some mistakes in .NET programming.&lt;/P&gt;
&lt;P&gt;A &lt;EM&gt;C++ Thread&lt;/EM&gt; is very resource heavy. It is associated with a lot of dynamically allocated memory and some OS handles. So it had better to be cleaned up ASAP after its corresponding &lt;EM&gt;OS thread&lt;/EM&gt; dies. &lt;EM&gt;C++ Thread&lt;/EM&gt; class has a reference count. For its object to be deleted, the ref count has to be dropped to 0 (Rotor: &lt;EM&gt;Thread::DecExternalCount&lt;/EM&gt; in &lt;EM&gt;vm\threads.cpp&lt;/EM&gt;). One interesting point is that the &lt;EM&gt;C# Thread&lt;/EM&gt; object actually keeps a reference to its associated &lt;EM&gt;C++ Thread&lt;/EM&gt;, so a live &lt;EM&gt;C# Thread&lt;/EM&gt; object could keep its &lt;EM&gt;C++ Thread&lt;/EM&gt; from being deleted even if the &lt;EM&gt;OS thread&lt;/EM&gt; is already dead. (On the other hand,&lt;EM&gt; C++ Thread&lt;/EM&gt; also has a reference to &lt;EM&gt;C# Thread&lt;/EM&gt;, but it will break the circle when its own ref count drops to 1). Because &lt;EM&gt;C# Thread&lt;/EM&gt; is a managed object, its lifetime is mostly determined by users. Plus, &lt;EM&gt;C# Thread&lt;/EM&gt; class has a finalizer, so its lifetime will be extended at least one GC.&amp;nbsp; So if user code caches the &lt;EM&gt;C# Thread&lt;/EM&gt; objects or have some ill-behaved finalizers (in &lt;A href="https://blogs.msdn.com/yunjin/archive/2005/07/05/435726.aspx"&gt;another blog entry&lt;/A&gt;, I mentioned wrong-doing finalizer on one object could prevent all other object's fianlizer from running), "dead" &lt;EM&gt;C++ Thread&lt;/EM&gt; objects&amp;nbsp;may accumulate over time and some "memory leak" will be observed.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;I have an example here to demo the problem and how to debug it using windbg + SOS. In this process, there are 202 &lt;EM&gt;C++ Thread&lt;/EM&gt; objects. Among which 160 are "dead", meaning their associated &lt;EM&gt;OS threads&lt;/EM&gt; are dead. Number of total threads in &lt;EM&gt;Thread Store&lt;/EM&gt; and dead/unstarted threads are showed in "!threads" output. For a "live" thread, OS and debugger thread ID are printed out for the entry, for a "dead" thread, "XXX" is marked at beginning of the line:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:043&amp;gt; !threads&lt;BR&gt;ThreadCount: 202&lt;BR&gt;UnstartedThread: 0&lt;BR&gt;BackgroundThread: 1&lt;BR&gt;PendingThread: 0&lt;BR&gt;DeadThread: 160&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;&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;&amp;nbsp; PreEmptive&amp;nbsp;&amp;nbsp; GC Alloc&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Lock&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ID&amp;nbsp; ThreadOBJ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; State&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Context&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Domain&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Count APT Exception&lt;BR&gt;&amp;nbsp; 0 0x1138 0x0015a298&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x20 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 Ukn&lt;BR&gt;&amp;nbsp; 1 0x1148 0x00152530&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1220 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn (Finalizer)&lt;BR&gt;&amp;nbsp; 3 0x114c 0x00177548&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp; 4 0x1150 0x00177878&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp; 5 0x1154 0x00177c08&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;… &lt;BR&gt;&amp;nbsp;42 0x11e4 0x00180460&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;&amp;nbsp;22 0x11e8 0x00180838&amp;nbsp;&amp;nbsp; 0x2001020 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00180c10&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00180fe8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x001813c0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00181750&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00181b28&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x00181f00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x001822d8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 0x00149ac8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;… //continue with a huge list&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;BR&gt;Now I want to find out why all the "dead" &lt;EM&gt;C++ Thread&lt;/EM&gt; objects are still around. First I could check its ref count if I have symbols for mscorwks.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;//0x00180c10 is a dead ThreadOBJ I picked from !Threads output&lt;BR&gt;0:043&amp;gt; dt mscorwks!Thread 0x00180c10 m_ExternalRefCount&lt;BR&gt;&amp;nbsp;&amp;nbsp; +0x0cc m_ExternalRefCount : 1&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Since the ref count is 1, if this &lt;EM&gt;C++ Thread&lt;/EM&gt; object has a &lt;EM&gt;C# Thread&lt;/EM&gt; object associated with it, the C# object must be the last reference. I could verify if that is the case by checking the C++ object's &lt;EM&gt;m_ExposedObject&lt;/EM&gt; field. It is a weak GC handle (a unmovable pointer to GC reference which doesn't counted as root of the GC object), so dereference it will get the managed object. As mentioned before, &lt;EM&gt;C++ Thread&lt;/EM&gt; object also has a strong handle (&lt;EM&gt;m_StrongHndToExposedObject&lt;/EM&gt; field)&amp;nbsp;to the &lt;EM&gt;C# object&lt;/EM&gt;, but it already cleared the strong handle when ref count drops to 1 to avoid circular reference.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:043&amp;gt; dt mscorwks!Thread 0x00180c10 m_ExposedObject&lt;BR&gt;&amp;nbsp;&amp;nbsp; +0x0c0 m_ExposedObject : 0x00a71054 &lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:043&amp;gt; dp 0x00a71054 l1&lt;BR&gt;00a71054&amp;nbsp; 00c5c714&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:043&amp;gt; !do 00c5c714&lt;BR&gt;Name: System.Threading.Thread&lt;BR&gt;MethodTable 0x79bb8384&lt;BR&gt;EEClass 0x79bb85b0&lt;BR&gt;Size 60(0x3c) bytes&lt;BR&gt;GC Generation: 0&lt;BR&gt;mdToken: 0x020000eb&amp;nbsp; (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)&lt;BR&gt;FieldDesc*: 0x79bb8614&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Field&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Offset&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; Type&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Attr&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Value Name&lt;BR&gt;0x79bb8384 0x4000330&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x4&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_Context&lt;BR&gt;0x79bb8384 0x4000331&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x8&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_LogicalCallContext&lt;BR&gt;0x79bb8384 0x4000332&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0xc&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_IllogicalCallContext&lt;BR&gt;0x79bb8384 0x4000333&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x10&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_Name&lt;BR&gt;0x79bb8384 0x4000334&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x14&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_ExceptionStateInfo&lt;BR&gt;0x79bb8384 0x4000335&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x18&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_Delegate&lt;BR&gt;0x79bb8384 0x4000336&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1c&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_PrincipalSlot&lt;BR&gt;0x79bb8384 0x4000337&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x20&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_ThreadStatics&lt;BR&gt;0x79bb8384 0x4000338&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x24&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_ThreadStaticsBits&lt;BR&gt;0x79bb8384 0x4000339&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x28&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_CurrentCulture&lt;BR&gt;0x79bb8384 0x400033a&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x2c&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_CurrentUICulture&lt;BR&gt;0x79bb8384 0x400033b&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x30&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Int32&amp;nbsp;&amp;nbsp; instance 2 m_Priority&lt;BR&gt;0x79bb8384 0x400033c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x34&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Int32&amp;nbsp;&amp;nbsp; instance 1575952 DONT_USE_InternalThread&lt;BR&gt;0x79bb8384 0x400033d&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0&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; CLASS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; shared&amp;nbsp;&amp;nbsp; static m_LocalDataStoreMgr&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;gt;&amp;gt; Domain:Value 0x00149ac8:0x00c05338 &amp;lt;&amp;lt;&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Then I want to check root of the &lt;EM&gt;C# Thread&lt;/EM&gt; object to see who keeps it alive:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:043&amp;gt; !gcroot 00c5c714&lt;BR&gt;Scan Thread 0 (0x1138)&lt;BR&gt;ESP:12f69c:Root:0xc5b3f4(System.Object[])-&amp;gt;0xc5c714(System.Threading.Thread)&lt;BR&gt;…&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So there is an array who keeps a reference to a "dead" &lt;EM&gt;C# Thread&lt;/EM&gt;. This looks interesting. I could check all other &lt;EM&gt;C# Thread&lt;/EM&gt; objects in the process using !DumpHeap command. !DumpHeap could dump objects in GC heap for a particular type specified by "-type" option:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:043&amp;gt; !DumpHeap -type System.Threading.Thread&lt;BR&gt;&amp;nbsp;&amp;nbsp; Address&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Size&amp;nbsp; Gen&lt;BR&gt;0x00c054c8 0x79bb8384&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 System.Threading.Thread &lt;BR&gt;0x00c5b730 0x79bc81d4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 28&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.ThreadStart &lt;BR&gt;0x00c5b74c 0x79bb8384&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.Thread &lt;BR&gt;0x00c5b7bc 0x79bc81d4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 28&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.ThreadStart &lt;BR&gt;0x00c5b7d8 0x79bb8384&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.Thread &lt;BR&gt;0x00c5b820 0x79bc81d4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 28&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.ThreadStart &lt;BR&gt;0x00c5b83c 0x79bb8384&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.Thread &lt;BR&gt;0x00c5b884 0x79bc81d4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 28&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.ThreadStart &lt;BR&gt;0x00c5b8a0 0x79bb8384&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.Thread &lt;BR&gt;0x00c5b8e8 0x79bc81d4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 28&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.ThreadStart &lt;BR&gt;0x00c5b904 0x79bb8384&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.Thread &lt;BR&gt;0x00c5b94c 0x79bc81d4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 28&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.ThreadStart &lt;BR&gt;0x00c5b968 0x79bb8384&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.Thread &lt;BR&gt;0x00c5b9b0 0x79bc81d4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 28&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 System.Threading.ThreadStart &lt;BR&gt;…//long list&lt;BR&gt;total 401 objects&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Because !DumpHeap match type by string, so it also dumps &lt;EM&gt;ThreadStart&lt;/EM&gt; objects. Because every &lt;EM&gt;C# Thread&lt;/EM&gt; object created by user code always has a &lt;EM&gt;ThreadStart&lt;/EM&gt; object (but &lt;EM&gt;C# Thread&lt;/EM&gt; created by &lt;EM&gt;System.Thread.CurrentThread &lt;/EM&gt;may not have a &lt;EM&gt;ThreadStart&lt;/EM&gt;), so they show up as a pair. among 401 such objects,&amp;nbsp;200 are &lt;EM&gt;C# Thread&lt;/EM&gt; objects, roughly match the number of &lt;EM&gt;C++ Thread&lt;/EM&gt; objects (the number doesn't have to be the same because not every &lt;EM&gt;C++ Thread&lt;/EM&gt; object has a C# counterpart created). Generation for most of &lt;EM&gt;C# Thread&lt;/EM&gt; objects are 2, meaning they already survive at least 2 GCs. When I track roots of those &lt;EM&gt;C# Thread&lt;/EM&gt; objects, they all point to the array. In this case, we need to look closely to the source to see whether it is necessary to cache all the &lt;EM&gt;C# Thread&lt;/EM&gt; objects in an array.&lt;/P&gt;
&lt;P&gt;Another related topic is that CLR relies on &lt;EM&gt;DLL_THREAD_DETACH&lt;/EM&gt; notification to mscorwks.dll's DllMain (Rotor: &lt;EM&gt;EEDllMain&lt;/EM&gt; in &lt;EM&gt;vm\ceemain.cpp&lt;/EM&gt;) to know an OS thread is dead, thus detach the related &lt;EM&gt;C++ Thread&lt;/EM&gt;. Using &lt;EM&gt;TerminateThread&lt;/EM&gt; API is already notoriously bad&amp;nbsp;in unmanaged programming, here we see another reason not to call it in managed code: if &lt;EM&gt;TerminateThread&lt;/EM&gt; is called on a managed OS thread, among other bad effect (e.g. back out code not executed), CLR will not get thread detach notification. Because &lt;EM&gt;C++ Thread&lt;/EM&gt; object has references to &lt;EM&gt;OS thread's&lt;/EM&gt; stack address, failing to detach it from the OS thread will cause crash at random place.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=457150" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="Rotor code explanation" scheme="http://blogs.msdn.com/yunjin/archive/tags/Rotor+code+explanation/default.aspx" /><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>Thread, System.Threading.Thread, and !Threads (I)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/08/25/456355.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/08/25/456355.aspx</id><published>2005-08-25T20:26:00Z</published><updated>2005-08-25T20:26:00Z</updated><content type="html">&lt;P&gt;If you use SOS’s !Threads command during debugging a lot,&amp;nbsp; you should be familiar with such output:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;BR&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:003&amp;gt; !threads&lt;BR&gt;PDB symbol for mscorwks.dll not loaded&lt;BR&gt;Loaded Son of Strike data table version 5 from "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorwks.dll"&lt;BR&gt;ThreadCount: 12&lt;BR&gt;UnstartedThread: 5&lt;BR&gt;BackgroundThread: 1&lt;BR&gt;PendingThread: 0&lt;BR&gt;DeadThread: 5&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;&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;&amp;nbsp; PreEmptive&amp;nbsp;&amp;nbsp; GC Alloc&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Lock&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ID&amp;nbsp; ThreadOBJ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; State&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Context&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Domain&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Count APT Exception&lt;BR&gt;&amp;nbsp; 0&amp;nbsp; 0xb74 0x0014f230&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x20 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 Ukn&lt;BR&gt;&amp;nbsp; 2&amp;nbsp; 0xb58 0x00157cf8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1220 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn (Finalizer)&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x001665f0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016d348&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1400 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016d510&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016d9d0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1400 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016db98&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016e248&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1400 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016e410&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016e740&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1400 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016e908&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1820 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;BR&gt;XXX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 0x0016ec98&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1400 Enabled&amp;nbsp; 0x00000000:0x00000000 x00149aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0 Ukn&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;Have you ever wondered what exactly are in the list? Why the number of threads listed here doesn’t match the number of "real" threads in the process (in the example above, I only have 4 threads in the process, but !Threads shows 12)? Why some "real" threads have entries here, some don't? Maybe they are managed System.Threading.Thread objects (but the number in the list might not match number of Thread objects either)? Answers to those questions are tied to how CLR implements threads and manages thread information.&lt;BR&gt;&amp;nbsp;&lt;BR&gt;CLR provides classes in System.Threading namespace as threading APIs. As you know, threading is implemented by utilizing native threads in underlying OS (Windows, in CLR case). CLR just piggybacks managed threads to native OS threads. Users use BCL System.Threading.Thread objects (I’ll call it as &lt;EM&gt;C# Thread&lt;/EM&gt; below) to control managed threads just as thread HANDLE is used to control to windows native threads. If you ever checked contents of a &lt;EM&gt;C# Thread&lt;/EM&gt; object, you will find it is quite small (here I use SOS !DumpObj command, you could also see it using Visual Studio or other managed debuggers):&lt;BR&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;BR&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:003&amp;gt; !DumpObj 0x00c03248 &lt;BR&gt;Name: System.Threading.Thread&lt;BR&gt;MethodTable 0x79bb8384&lt;BR&gt;EEClass 0x79bb85b0&lt;BR&gt;Size 60(0x3c) bytes&lt;BR&gt;GC Generation: 0&lt;BR&gt;mdToken: 0x020000eb&amp;nbsp; (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)&lt;BR&gt;FieldDesc*: 0x79bb8614&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Field&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Offset&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; Type&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Attr&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Value Name&lt;BR&gt;0x79bb8384 0x4000330&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x4&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_Context&lt;BR&gt;0x79bb8384 0x4000331&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x8&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_LogicalCallContext&lt;BR&gt;0x79bb8384 0x4000332&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0xc&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_IllogicalCallContext&lt;BR&gt;0x79bb8384 0x4000333&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x10&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_Name&lt;BR&gt;0x79bb8384 0x4000334&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x14&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_ExceptionStateInfo&lt;BR&gt;0x79bb8384 0x4000335&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x18&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_Delegate&lt;BR&gt;0x79bb8384 0x4000336&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x1c&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_PrincipalSlot&lt;BR&gt;0x79bb8384 0x4000337&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x20&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_ThreadStatics&lt;BR&gt;0x79bb8384 0x4000338&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x24&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_ThreadStaticsBits&lt;BR&gt;0x79bb8384 0x4000339&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x28&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_CurrentCulture&lt;BR&gt;0x79bb8384 0x400033a&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x2c&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; CLASS&amp;nbsp;&amp;nbsp; instance 0x00000000 m_CurrentUICulture&lt;BR&gt;0x79bb8384 0x400033b&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x30&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Int32&amp;nbsp;&amp;nbsp; instance 2 m_Priority&lt;BR&gt;0x79bb8384 0x400033c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x34&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Int32&amp;nbsp;&amp;nbsp; instance 1498008 DONT_USE_InternalThread&lt;BR&gt;0x79bb8384 0x400033d&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0&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; CLASS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; shared&amp;nbsp;&amp;nbsp; static m_LocalDataStoreMgr&lt;BR&gt;&lt;/FONT&gt;&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;BR&gt;CLR actually needs much more information about a thread than fields of the &lt;EM&gt;C# Thread&lt;/EM&gt; class, and such information is needed in CLR's unmanaged part where it's not easy to access managed objects. So inside Execution Engine (so far Execution Engine is still written in unmanaged code), there is an unmanaged C++ class also called Thread (let me call&amp;nbsp; it &lt;EM&gt;C++ Thread&lt;/EM&gt;) to keep all information for an OS native thread (&lt;EM&gt;OS thread&lt;/EM&gt;). In Rotor, this class is defined in &lt;EM&gt;vm\threads.h.&lt;/EM&gt; &lt;BR&gt;&amp;nbsp;&lt;BR&gt;CLR needs to create a &lt;EM&gt;C++ Thread&lt;/EM&gt; object for every &lt;EM&gt;OS thread&lt;/EM&gt; EE knows of, that is, every thread which ever ran managed code. Such threads could either be (a) created explicitly by users using &lt;EM&gt;C# Thread.Start&lt;/EM&gt;, (b) an unmanaged &lt;EM&gt;OS thread&lt;/EM&gt; who has ever visited managed world, e.g, through interop, or (c) a special &lt;EM&gt;OS thread&lt;/EM&gt; in CLR which might run managed code. For case a, when a user creates a &lt;EM&gt;C# Thread&lt;/EM&gt; object, CLR will create a &lt;EM&gt;C++ Thread&lt;/EM&gt; object, link it to the &lt;EM&gt;C# Thread&lt;/EM&gt; object, and mark it as unstarted (Rotor: &lt;EM&gt;SetupUnstartedThread&lt;/EM&gt; in &lt;EM&gt;vm\threads.cpp&lt;/EM&gt;). Once &lt;EM&gt;Start&lt;/EM&gt; method is called on the &lt;EM&gt;C# Thread&lt;/EM&gt; object, CLR will create an &lt;EM&gt;OS thread&lt;/EM&gt;, in the &lt;EM&gt;OS thread&lt;/EM&gt;’s ThreadPproc (Rotor:&lt;EM&gt; ThreadNative::KickOffThread&lt;/EM&gt; in &lt;EM&gt;vm\ComSynchronizable.cpp&lt;/EM&gt;), CLR will save the &lt;EM&gt;C++ Thread&lt;/EM&gt; object’s address to the &lt;EM&gt;OS thread&lt;/EM&gt;'s TLS (Thread Local Storage) and mark it to be started (Rotor: &lt;EM&gt;ThreadStore::TransferStartedThread&lt;/EM&gt; in &lt;EM&gt;vm\threads.cpp&lt;/EM&gt;); For case b, at entry point for an unmanaged &lt;EM&gt;OS thread&lt;/EM&gt; to managed world, CLR will create a &lt;EM&gt;C++ Thread&lt;/EM&gt; object and also use TLS to associate it with the &lt;EM&gt;OS thread&lt;/EM&gt; (Rotor: &lt;EM&gt;SetupThread&lt;/EM&gt; in &lt;EM&gt;vm\threads.cpp&lt;/EM&gt;); Case c is similar to case b, except CLR might set up &lt;EM&gt;C++ Thread&lt;/EM&gt; earlier. &lt;BR&gt;&amp;nbsp;&lt;BR&gt;In any case, the &lt;EM&gt;C++ Thread&lt;/EM&gt; object is the primary place for CLR to store information regarding to a managed thread. When CLR needs to access the information, it will just fetch the object from the&lt;EM&gt; OS thread&lt;/EM&gt;'s TLS. In that sense, the &lt;EM&gt;C# Thread&lt;/EM&gt; is more like a managed proxy for the &lt;EM&gt;C++ Thread&lt;/EM&gt;. In fact, for case b and c, there will be no &lt;EM&gt;C# Thread&lt;/EM&gt; objects created unless users call &lt;EM&gt;System.Threading.Thread.CurrentThread&lt;/EM&gt;. &lt;EM&gt;C++ Thread&lt;/EM&gt; tracks its corresponding &lt;EM&gt;C# Thread&lt;/EM&gt; using a GCHandle (&lt;EM&gt;m_ExposedObject&lt;/EM&gt; field in &lt;EM&gt;C++ Thread&lt;/EM&gt; object); &lt;EM&gt;C# Thread&lt;/EM&gt; tracks its &lt;EM&gt;C++ Thread&lt;/EM&gt; using a native pointer(&lt;EM&gt;DONT_USE_InternalThread&lt;/EM&gt; field in &lt;EM&gt;C# Thread&lt;/EM&gt;). You could verify this circular reference in debugger if you have symbols for mscorwks.dll:&lt;BR&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;BR&gt;&lt;EM&gt;&lt;FONT size=2&gt;0:003&amp;gt; !do 0x00c03248 &lt;BR&gt;Name: System.Threading.Thread&lt;BR&gt;…&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Field&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Offset&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; Type&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Attr&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Value &lt;BR&gt;…&lt;BR&gt;0x79bb8384 0x400033c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x34&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Int32&amp;nbsp;&amp;nbsp; instance 1498008 DONT_USE_InternalThread&lt;BR&gt;…&lt;BR&gt;&amp;nbsp;&lt;BR&gt;0:013&amp;gt; dt mscorwks!Thread 0n1498008&lt;BR&gt;…&lt;BR&gt;+0x0c0 m_ExposedObject&amp;nbsp; : 0x00a710e4&lt;BR&gt;…&lt;BR&gt;&amp;nbsp;&lt;BR&gt;0:013&amp;gt; dp 0x00a710e4 l1&lt;BR&gt;00a710e4&amp;nbsp; 00c03248&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;CLR uses a data structure called &lt;EM&gt;Thread Store&lt;/EM&gt; (Rotor: &lt;EM&gt;ThreadStore&lt;/EM&gt; in &lt;EM&gt;vm\threads.h&lt;/EM&gt;) to keep all &lt;EM&gt;C++ Threads&lt;/EM&gt;. What you see in output of !Threads command is actually list of &lt;EM&gt;C++ Threads&lt;/EM&gt; in &lt;EM&gt;Thread Store&lt;/EM&gt;. The “ThreadOBJ” field is address of a &lt;EM&gt;C++ Thread&lt;/EM&gt; object. Other fields are important information about the &lt;EM&gt;C++ Thread&lt;/EM&gt;, including OS thread ID for the corresponding &lt;EM&gt;OS thread&lt;/EM&gt;. Here you could see not every live &lt;EM&gt;OS thread&lt;/EM&gt; has a &lt;EM&gt;C++ Thread&lt;/EM&gt;, which could be explained by the fact that CLR only creates a &lt;EM&gt;C++ Thread&lt;/EM&gt; for an &lt;EM&gt;OS thread&lt;/EM&gt; which ever runs managed code. Meanwhile you may also find some &lt;EM&gt;C++ Threads&lt;/EM&gt; don't have an &lt;EM&gt;OS thread&lt;/EM&gt; associated with them (the ID fields are “XXX”). They are either (a)unstarted, (b) failed to started, (c)used to represent an live &lt;EM&gt;OS thread&lt;/EM&gt; which is now dead. For case (a), CLR will wait until &lt;EM&gt;C# Thread.Start&lt;/EM&gt; is called and create an &lt;EM&gt;OS thread&lt;/EM&gt; for it then; for (b) and (c), the &lt;EM&gt;C++ Thread&lt;/EM&gt;s object will be deleted some time later.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=456355" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="Rotor code explanation" scheme="http://blogs.msdn.com/yunjin/archive/tags/Rotor+code+explanation/default.aspx" /><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>Special threads in CLR</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/07/05/435726.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/07/05/435726.aspx</id><published>2005-07-05T19:52:00Z</published><updated>2005-07-05T19:52:00Z</updated><content type="html">&lt;P&gt;&lt;STRONG&gt;Question:&lt;/STRONG&gt; How many threads does a typical managed process have when it just starts to run?&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Answer:&lt;/STRONG&gt; regardless how many threads the user creates, there are at least 3 threads for a common managed process after CLR starts up: a main thread which starts CLR and run user's Main method, CLR debugger helper thread which provides debugging service for interop debuggers like Visual Studio, and the finalizer thread which runs finalizers for unreachable objects. Depends on what the program does, CLR might create more threads to perform special tasks.&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Sometimes it is important to know what "special" threads would be created in CLR so we could understand better the implicit impact of our managed programs. Here is a list of most common special threads:&amp;nbsp;&lt;/P&gt;
&lt;P&gt;1. Finalizer thread. The thread is to run finalizers for "dead" objects. This thread is created when GC heap is initialized during EE start up. In Rotor, the thread proc for the thread is &lt;EM&gt;GCHeap::FinalizerThreadStart&lt;/EM&gt; in &lt;EM&gt;vm\gcee.cpp&lt;/EM&gt;. Because GC is undeterministic and finalizers are executed in a separate thread, you can't predict when exactly an object will be finalized. Because there is only one thread to run all finalizers, if one finalizer is blocked, no other finalizers could run. So it is discouraged to take any lock in finalizer. Also see &lt;a href="http://blogs.msdn.com/maoni/archive/2004/11/04/252697.aspx"&gt;Maoni Stephens's blog&lt;/A&gt; for details about finalizer thread.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;2. Debugger helper thread. As its name suggests, this thread helps debuggers (mixed mode&amp;nbsp;and managed debugger, but not pure unmanaged debug like windbg)&amp;nbsp;to get information of the managed process and to execute certain debugging operations. The thread is created when EE initializes debugger during start up. In Rotor, the thread proc for this thread is &lt;EM&gt;DebuggerRCThread::ThreadProcStatic (debug\ee\Rcthread.cpp)&lt;/EM&gt;. Also see &lt;a href="http://blogs.msdn.com/jmstall/archive/2004/10/13/241828.aspx"&gt;Mike Stall's blog &lt;/A&gt;about impact of this helper thread。&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;3. Concurrent GC thread (doesn't exist in Rotor). As explained in &lt;a href="http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx"&gt;Maoni&lt;/A&gt; and &lt;a href="http://blogs.msdn.com/clyon/archive/2004/09/08/226981.aspx"&gt;Chris Lyon's blog&lt;/A&gt;, concurrent GC is a special GC mode which allows garbage to be collected while managed threads are running simultaneously. To achieve this goal, CLR creates a thread to perform GC concurrently with user threads. The thread is only created when CLR decides to do a concurrent GC (even when concurrent GC mode is on, not every GC is concurrent, read Maoni's blog for details) and will be recycled when there are no concurrent GC work to do. &lt;BR&gt;&lt;/P&gt;
&lt;P&gt;4. Server GC threads (doesn't exist in Rotor). Maoni and Chris also explained Server GC mode where on multi-process machine CLR creates one GC heap for each CPU and one thread to do GC for each heap. When Server GC mode is enabled, server GC threads will be created at EE start up time when GC heaps are initialized. &lt;/P&gt;
&lt;P&gt;&lt;BR&gt;5. App Domain unload helper thread. In CLR V1.X, when a thread requests to unload an App Domain and the thread is in that App Domain itself, it needs to create a worker thread to do the unloading work. The worker thread will be dead once the target AD is unloaded. In Rotor, the thread starts with &lt;EM&gt;UnloadThreadWorker.ThreadStart (bcl\system\Appdomain.cs)&lt;/EM&gt;. In Whidbey, all AD unload work is performed in a special thread regardless whether the requesting thread is in the unloading domain. The helper thread is created when first non-default App Domain is created (default domain is never unloaded) and will stay alive since then. Also see &lt;a href="http://blogs.msdn.com/cbrumme/archive/2003/06/01/51466.aspx"&gt;Chris Brumme's blog&lt;/A&gt; about details of AD unload.&lt;/P&gt;
&lt;P&gt;6. Threadpool threads. Depends on how a program use CLR threadpool, CLR might create threads of a varieties of types. There is only one thread for some thread type. For other types, number of threads is related to number of CPUs, the work load, and some user configurable settings. The thread types including wait threads (threads to perform asynchronized wait, could be more than one); worker threads (threads to execute user work item, could be more than one); Completion port threads (threads wait for completion port IO in Windows, could be more than one, doesn't exist in Rotor); Gate thread (thread help to monitor status of completion port threads and worker threads, only one); Timer thread (thread manages timer queue, only one). &lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=435726" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="Rotor code explanation" scheme="http://blogs.msdn.com/yunjin/archive/tags/Rotor+code+explanation/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>Desctructor, finalizer, and Dispose - Part2.C++/CLI in Whidbey</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/06/16/429942.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/06/16/429942.aspx</id><published>2005-06-17T02:41:00Z</published><updated>2005-06-17T02:41:00Z</updated><content type="html">&lt;P&gt;I changed the program in &lt;A href="https://blogs.msdn.com/yunjin/archive/2005/06/16/429806.aspx"&gt;previous post &lt;/A&gt;to use new Whidbey syntax.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;using namespace System;&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;ref class RefT&lt;BR&gt;{&lt;BR&gt;public:&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;RefT () {Console::WriteLine ("RefT::RefT");}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ~RefT () {Console::WriteLine ("RefT::~RefT");}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;!RefT () {Console::WriteLine ("RefT::!RefT");}&lt;BR&gt;};&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;value class ValueT&lt;BR&gt;{&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //constructor is not allowed for value type&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //destructor is not allowed for value type&lt;BR&gt;};&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;int main()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { //1. finalizer will be called in asynchronizied fashion&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; RefT ^ rrt = gcnew RefT;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{ //2. Dispose is called at “delete” and finalizer is suppressed&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RefT ^ rrt = gcnew RefT;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete rrt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{ //3. Dispose is called at end of the block and finalizer is suppressed&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;RefT rt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ValueT vt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;ValueT ^ pvt = gcnew ValueT;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ValueT * pvt = new ValueT;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp; return 0;&lt;BR&gt;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;First thing to notice is &lt;EM&gt;__gc&lt;/EM&gt; and &lt;EM&gt;__value&lt;/EM&gt; are replaced by &lt;EM&gt;ref&lt;/EM&gt; and &lt;EM&gt;value&lt;/EM&gt;, this is definitely clearer; then &lt;EM&gt;RefT&lt;/EM&gt; now could have another method &lt;EM&gt;!RefT&lt;/EM&gt;. What does this new methods do and how is related to the other ones? Having checked IL generated by Whidbey cl, I found &lt;EM&gt;RefT&lt;/EM&gt; is translated into something like:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;class RefT : IDisposable&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //constructor&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; RefT ()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine (“RefT::RefT”);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //Dispose methods&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Dispose (bool disposing)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (disposing)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ~Ref();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&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; try&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&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; !Ref();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; finally&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&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; Object.Finalize();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;Dispose ()&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dispose (true);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SuppressFinalize (this);&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;//finalizer&lt;BR&gt;Finalize ()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;Dispose (false);&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;//body of Dispose and Finalize&lt;BR&gt;&amp;nbsp;~RefT ()&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine (“RefT::~RefT”);&lt;BR&gt;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;!RefT ()&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine (“RefT::!RefT”);&lt;BR&gt;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Basically a reference type with destructor (method starts with ~) implements &lt;EM&gt;IDisposable&lt;/EM&gt; interface. Its destructor becomes &lt;EM&gt;Dispose&lt;/EM&gt; method; we could also define finalizer for a reference type using the “!” syntax. According to my test, those two are independent to each other. If I only define “~” function, not the “!” one, the class will only have &lt;EM&gt;Dispose&lt;/EM&gt; methods, no &lt;EM&gt;Finalize&lt;/EM&gt; will be generated although &lt;EM&gt;Dispose&lt;/EM&gt; still call &lt;EM&gt;SuppressFinalize&lt;/EM&gt;; if I only define “!” method without the “~” one, I got a compiler warning and a class which has a finalizer but doesn't implement &lt;EM&gt;IDisposable&lt;/EM&gt;. &lt;/P&gt;
&lt;P&gt;Other new things include using tracking handle (“^”) instead of pointer for reference to GC type and gcnew to indicate the memory is allocated in managed heap.&lt;/P&gt;
&lt;P&gt;All the new designs make CLR concepts (reference/value type, Finalize, Dispose, managed heap) first class citizen in C++. As a CLR team member, I think this is much clearer than special annotation or mapping new concepts to existing features which have different semantics. However, from a C++ user's point of view, the changes seem to draw C++ closer to C#. I'm not sure if everyone would love them.&lt;/P&gt;
&lt;P&gt;Back to finalization: for tracking handles, things are still similar to pointers in V1.X. If &lt;EM&gt;delete&lt;/EM&gt; is not called on a tracking handle (like the first block in &lt;EM&gt;main&lt;/EM&gt;), some time in the future finalizer will run and GC will collect the object; if "&lt;EM&gt;delete"&lt;/EM&gt; is called (like the 2nd block in &lt;EM&gt;main&lt;/EM&gt;), &lt;EM&gt;Dispose&lt;/EM&gt; (~ function) is called and finalizer is suppressed, the object will still be GCed later. &lt;/P&gt;
&lt;P&gt;The 3rd block in &lt;EM&gt;main&lt;/EM&gt; is the most interesting one: we could create reference type object “on stack” (of course, the object is still in heap, we just save a reference in stack) and this “stack object” has the traditional C++ finalization semantics: when the variable goes out of scope, its destructor (&lt;EM&gt;Dispose&lt;/EM&gt; method) will be called automatically if it has one. The generated IL for block 3 looks to be something like this:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;RefT r = new RefT;&lt;BR&gt;try &lt;BR&gt;{&lt;BR&gt;}&lt;BR&gt;finally&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;((IDisposable)r).Dispose ();&lt;BR&gt;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This looks almost same as C#'s &lt;EM&gt;using&lt;/EM&gt; statement. Implementing C++'s automatic destruction by Disposable pattern is a brilliant idea. I just worry the new “stack object” syntax will create new confusion about where the object really lives. I tend to think the stack object is a holder, similar to &lt;EM&gt;auto_ptr&lt;/EM&gt;, which holds reference to an object in heap and will delete the object when it goes out of scope. I did have question at the beginning about whether this holder tracks ownership of the object (like &lt;EM&gt;auto_ptr&lt;/EM&gt;) or does ref counting (like traditional smart pointer) to make sure if multiple holders reference the same object, only the last one dispose the object. But there seems to be no way to make two holders to point to the same object. E.g: this code doesn't compile with compliant “operator=” isn't available for &lt;EM&gt;RefT&lt;/EM&gt;, even if you define operator= for &lt;EM&gt;RefT&lt;/EM&gt;, it only applies to the object in heap, not the holder on stack:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;RefT rt1;&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; RefT rt2;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rt1 = rt2;&lt;BR&gt;}&amp;nbsp;&amp;nbsp; &lt;BR&gt;//I&amp;nbsp;assumed&amp;nbsp;rt2 would reference to a disposed object here&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;After all this “holder” is more of syntax sugar&amp;nbsp;other than&amp;nbsp;a real smart pointer class, it's easy to guarantee they don't represent the same object in heap. My worry&amp;nbsp;might be&amp;nbsp;unnecessary, but it's just an example how it could be confused. &lt;/P&gt;
&lt;P&gt;With so many changes, it's inappropriate to call it managed extension to C++ anymore. Now people refer the new language mostly as C++/CLI. I really feel sorry for those who have to rewrite their C++ code for .NET platform again and again. But I think&amp;nbsp;Whidbey&amp;nbsp;lays down a foundation which could last for generations.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=429942" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>Desctructor, finalizer, and Dispose - Part 1.managed C++ extension in V1.X</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/06/16/429806.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/06/16/429806.aspx</id><published>2005-06-16T20:12:00Z</published><updated>2005-06-16T20:12:00Z</updated><content type="html">&lt;P&gt;As a C++ fan, I'm a long time admirer for deterministic finalization. I think introduction of garbage collection to C style language by Java and .Net is a huge improvement. However, I found lose of deterministic destructor is almost unacceptable when I first enter Java/.Net world. Of course I'm used to it now, but it's still quite confusing to me for C# to use C++ destructor syntax for Finalizer. And in managed extension of C++, destructor becomes something totally different for managed data type. I bet a lot of experienced C++ developers make mistake to use finalizer as if it was destructor when they first try .Net. So when I read the new changes in Whidbey version of C++ from &lt;a href="https://blogs.msdn.com:443/slippman/archive/2004/03/25/96067.aspx"&gt;Stan Lippman's blog&lt;/A&gt;, I'm very excited and can't wait to give it a try.&lt;/P&gt;
&lt;P&gt;But before we look into the new features, let's go over how old version of managed C++ handles destructors. I wrote this simple program:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;#using &amp;lt;mscorlib.dll&amp;gt;&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;using namespace System;&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;__gc class RefT&lt;BR&gt;{&lt;BR&gt;public:&lt;BR&gt;&amp;nbsp;&amp;nbsp; RefT () {Console::WriteLine ("RefT::RefT");}&lt;BR&gt;&amp;nbsp;&amp;nbsp; ~RefT () {Console::WriteLine ("RefT::~RefT");}&lt;BR&gt;};&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;__value class ValueT&lt;BR&gt;{&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ValueT () {Console::WriteLine ("ValueT::ValueT");}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //destructor is not allowed for value type&lt;BR&gt;};&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;int main()&lt;BR&gt;{&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { //1. auto-generated finalizer will be called in asynchronizied fashion&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RefT * prt = new RefT;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; { //2. Dispose is called at “delete” and finalizer will be suppressed&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; RefT * prt = new RefT;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; delete prt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ValueT vt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //value type can't be created in GC heap&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ValueT * pvt = __nogc new ValueT;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; delete pvt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 0;&lt;BR&gt;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I compiled it with V1.1 C++ compiler and checked generated IL code using ildasm. RefT is compiled to something like this:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;class RefT&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; RefT ()&lt;BR&gt;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;Console.WriteLine (“RefT::RefT”);&lt;BR&gt;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp; void Finalize ()&lt;BR&gt;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine (“Ref::~Ref”);&lt;BR&gt;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp; void __dtor ()&lt;BR&gt;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC.SuppressFinalize (this);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Finalize ();&lt;BR&gt;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Here we could see that C++ destructor is mapped to CLR finalizer and a method “__dtor” is added to call finalizer and SupressFinalize. &lt;/P&gt;
&lt;P&gt;In main, the first block creates a RefT object in heap and leaves it as garbage. Sometime later, finalizer (~RefT) will run and the object will be collected. In the second block, we “delete” the object. This is translated into a call to __dtor in IL. So “delete” acts more like Dispose method recommended by IDisposable pattern: the object is not freed but the contents are disposed and finalizer won't run on the object later. &lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=429806" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>Trivial debugging note - what catch(…) can’t catch</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/05/31/423544.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/05/31/423544.aspx</id><published>2005-05-31T23:22:00Z</published><updated>2005-05-31T23:22:00Z</updated><content type="html">&lt;P&gt;One day I was&amp;nbsp;debugging a problem where a Waston dialog popped up on a process. What surprised me was that on the stack where Waston was triggered, there was a unmanaged C++ function with a try-catch(…) block. To my understanding, this block should catch any user mode exception thrown in Windows, including exception from RaiseException call (e.g, C++ exceptions), AV, stack overflow, and etc. Why an exception could escape such a block and become unhandled (thus Waston showed up)? I found the exception was a debug break. In X86, it is triggered by opcode 0xCC or “int 3”. When I debugged into VCRT’s EH code, I found catch (…) deliberately let debug break go. It does make sense: debug break is meant to stop the debugger so source code should never handle it. I just never realized it before.&lt;/P&gt;
&lt;P&gt;Another interesting part is where this debug break was from, the code of the process never calls DebugBreak. After I debugged more, the problem turned out to be &lt;a href="http://blogs.msdn.com/yunjin/archive/2005/05/15/417569.aspx"&gt;the bug I mentioned in my previous blog entry: a premature GC issue&lt;/A&gt;. managed code passed a Delegate to unmanaged code without telling GC to extend its lifetime. When unmanaged code called the callback, the managed Delegate object was already collected so unmanaged code called into garbage memory. The memory happened to be filled with 0xCC so when the process tried to execute this code, it fired int 3, then Waston kicked in.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=423544" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /></entry><entry><title>Figure out variable lifetime using SOS</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/05/15/417569.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/05/15/417569.aspx</id><published>2005-05-15T10:06:00Z</published><updated>2005-05-15T10:06:00Z</updated><content type="html">There is a bug in this program below, try to see if you could catch it.&lt;BR&gt;
&lt;P class=MsoNormal&gt;&lt;STRONG&gt;Test.cs (compiled to DelegateExample.exe):&lt;/STRONG&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;FONT color=#000000&gt;&lt;EM&gt;using System;&lt;BR&gt;using System.Threading;&lt;BR&gt;using System.Runtime.InteropServices;&lt;/EM&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN&gt;&lt;FONT color=#000000&gt;
&lt;P class=MsoNormal&gt;&lt;BR&gt;&lt;EM&gt;class Test&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;delegate uint ThreadProc (IntPtr arg);&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;&amp;nbsp;private uint m;&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;&amp;nbsp;public Test (uint n)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;m = n;&lt;BR&gt;&amp;nbsp;}&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;&amp;nbsp;uint Reflect (IntPtr arg)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;Console.WriteLine (m);&lt;BR&gt;&amp;nbsp;&amp;nbsp;return m;&lt;BR&gt;&amp;nbsp;}&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;&amp;nbsp;static void Main ()&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;Test t = new Test (1);&lt;BR&gt;&amp;nbsp;&amp;nbsp;ThreadProc tp = new ThreadProc (t.Reflect);&lt;BR&gt;&amp;nbsp;&amp;nbsp;NewThread (tp);&lt;BR&gt;&amp;nbsp;&amp;nbsp;Thread.Sleep (1000);&lt;BR&gt;&amp;nbsp;}&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;&amp;nbsp;[DllImport("UsingCallback")]&lt;BR&gt;&amp;nbsp;static extern void NewThread (ThreadProc proc);&lt;BR&gt;}&lt;/EM&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal dir=ltr&gt;&lt;SPAN&gt;&lt;STRONG&gt;UsingCallback.cpp (compiled to UsingCallback.dll):&lt;o:p&gt;&lt;/o:p&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;FONT color=#000000&gt;&lt;EM&gt;_stdcall&amp;nbsp; void NewThread (LPTHREAD_START_ROUTINE cb)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;DWORD id = 0;&lt;BR&gt;&amp;nbsp;CreateThread (NULL, 0, cb, NULL, 0,&amp;amp;id);&lt;BR&gt;}&lt;/EM&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;EM&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;Yes, here is the problem: in the cs file, the managed code passes a Delegate object to unmanaged code which will create a new thread to call the delegate. Since unmanaged code has no way to tell CLR how it plans to use the object, from CLR's point of view, there are no live roots for the Delegate object after the line “&lt;EM&gt;&lt;FONT size=2&gt;NewThread (tp);&lt;/FONT&gt;&lt;/EM&gt;”. Thus the object is eligible to be garbage collected (GC) after the call, even if the new thread might not start yet. So it's possible for the Delegate to become&amp;nbsp;trash&amp;nbsp;before unmanaged code invokes it and cause unspecified failure. A fix is to add &lt;EM&gt;GC.KeepAlive&lt;/EM&gt; before &lt;EM&gt;Main&lt;/EM&gt; returns:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal dir=ltr&gt;&lt;EM&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Test t = new Test (1);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ThreadProc tp = new ThreadProc (t.Reflect);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NewThread (tp);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread.Sleep (1000);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC.KeepAlive (tp);&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;EM&gt;&amp;nbsp;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;One thing annoying about this kind of bug is that GC is nondeterministic, the program could work just fine 99% of time, but only crashes under stress situation. Another thing make the problem hard to find is that it's not very intuitive by looking at the source. You might know the theory that when a variable is not used anymore, it&amp;nbsp;will not be reported as a live root; but it would take quite some time to figure out at which point which variable is dead, plus there's no way to verify if CLR agrees with your analysis. &lt;/P&gt;
&lt;P class=MsoNormal&gt;I'll show you how to use SOS.dll to check the internal data structure used by CLR to determine variable lifetime. When JIT compiles code, it generates such variable aliveness information (GC info) for each method and saves it along with the machine code of the method. When GC happens, it will check GC info for every method in the stack to find out which variable&amp;nbsp;is alive and will use the live variables as object roots. GC info is highly compacted, but SOS.dll has “!GCInfo” command to crack it and show it in a human-readable way. This approach only works in assembly level, so stop reading if you are not interested in assembly language. :)&lt;/P&gt;
&lt;P class=MsoNormal&gt;I compiled test.cs above using Visual studio to a "Debug" build, and launched the program under Windbg. After the Main method is JITted, I could disassemly the generated native code of the method&amp;nbsp;using "!SOS.u" command:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;0:000&amp;gt; !u 02f00058 &lt;BR&gt;Will print '&amp;gt;&amp;gt;&amp;gt; ' at address: 02f00058&lt;BR&gt;Normal JIT generated code&lt;BR&gt;[DEFAULT] Void Test.Main()&lt;BR&gt;Begin 02f00058, size 60&lt;BR&gt;&amp;gt;&amp;gt;&amp;gt; 02f00058 55&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp&lt;BR&gt;02f00059 8bec&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp,esp&lt;BR&gt;02f0005b 83ec08&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sub&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,0x8&lt;BR&gt;02f0005e 57&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02f0005f 56&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;BR&gt;02f00060 53&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx&lt;BR&gt;02f00061 33ff&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xor&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi,edi&lt;BR&gt;02f00063 33db&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xor&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx,ebx&lt;BR&gt;02f00065 b9e850ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad50e8 (MT: Test)&lt;BR&gt;02f0006a e8a91fbcfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;02f0006f 8bf0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,eax&lt;BR&gt;02f00071 8bce&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,esi&lt;BR&gt;02f00073 ba01000000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edx,0x1&lt;BR&gt;02f00078 ff152051ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad5120] (Test..ctor)&lt;BR&gt;02f0007e 8bfe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi,esi&lt;BR&gt;02f00080 b9c451ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad51c4 (MT: Test/ThreadProc)&lt;BR&gt;02f00085 e88e1fbcfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;02f0008a 8bf0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,eax&lt;BR&gt;02f0008c 689350ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; 0xad5093&lt;BR&gt;02f00091 8bd7&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edx,edi&lt;BR&gt;02f00093 8bce&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,esi&lt;BR&gt;02f00095 ff152452ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad5224] (Test/ThreadProc..ctor)&lt;BR&gt;02f0009b 8bde&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx,esi&lt;BR&gt;02f0009d 8bcb&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,ebx&lt;BR&gt;02f0009f ff152c51ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad512c] (Test.NewThread)&lt;BR&gt;02f000a5 b9e8030000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0x3e8&lt;BR&gt;02f000aa ff155084bb79&amp;nbsp; call dword ptr [mscorlib_79990000+0x228450 (79bb8450)] (System.Threading.Thread.Sleep)&lt;BR&gt;02f000b0 90&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; nop&lt;BR&gt;02f000b1 5b&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx&lt;BR&gt;02f000b2 5e&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;BR&gt;02f000b3 5f&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02f000b4 8be5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,ebp&lt;BR&gt;02f000b6 5d&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp&lt;BR&gt;02f000b7 c3&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; ret&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;SOS's "!u" is similar to Windbg's "u", but it shows more data because managed code is self-describable. For example, for those indirect calls, if the target is a managed function, "!u" could tell us the function name.&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;To check its GC info, we need to get the method's MethodDesc first (Method descriptor, CLR's data structure to keep all information about one method). We could use "!ip2md" to find out the method desc from any instruction pointer in the method:&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;0:000&amp;gt; !ip2md 02f00058&lt;BR&gt;MethodDesc: 0x00ad50a8&lt;BR&gt;Jitted by normal JIT&lt;BR&gt;Method Name : [DEFAULT] Void Test.Main()&lt;BR&gt;MethodTable ad50e8&lt;BR&gt;Module: 151ad0&lt;BR&gt;mdToken: 06000003 (D:\projects\DelegateExample\bin\Debug\DelegateExample.exe)&lt;BR&gt;Flags : 10&lt;BR&gt;Method VA : 02f00058&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;This command&amp;nbsp;shows some important information about the method. To check GC info, we only need to pass the MethodDesc pointer itself to “!GCInfo”:&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;0:000&amp;gt; !gcinfo 0x00ad50a8&lt;BR&gt;Normal JIT generated code&lt;BR&gt;Method info block:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; method&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; = 0060&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; prolog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 9 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 7 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; count&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 1 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&amp;nbsp;&amp;nbsp;&amp;nbsp; = yes &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; saved reg.&amp;nbsp; mask&amp;nbsp;&amp;nbsp; = 000F&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp frame&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = yes &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; fully interruptible=yes &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; double align&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; security check&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; exception handlers = no &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; local alloc&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; edit &amp;amp; continue&amp;nbsp;&amp;nbsp;&amp;nbsp; = yes&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; varargs&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; argument&amp;nbsp;&amp;nbsp; count&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 0&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; stack frame size&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 2&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; untracked count&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 0&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ptr tab count&amp;nbsp; =&amp;nbsp;&amp;nbsp; 0&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at&amp;nbsp;&amp;nbsp; 0059&lt;BR&gt;60 E5 C0 45&amp;nbsp;&amp;nbsp;&amp;nbsp; | &lt;BR&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal&gt;Pointer table:&lt;BR&gt;F0 7B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 000B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDI becoming live&lt;BR&gt;5A&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 000D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EBX becoming live&lt;BR&gt;F0 42&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0017&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming live&lt;BR&gt;72&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0019&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming live&lt;BR&gt;4A&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 001B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming live&lt;BR&gt;F0 03&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0026&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming dead&lt;BR&gt;08&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0026&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming dead&lt;BR&gt;F0 44&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0032&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming live&lt;BR&gt;30&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0032&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming dead&lt;BR&gt;72&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0034&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming live&lt;BR&gt;57&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 003B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDX becoming live&lt;BR&gt;4A&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 003D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming live&lt;BR&gt;06&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0043&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming dead&lt;BR&gt;08&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0043&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming dead&lt;BR&gt;10&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0043&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDX becoming dead&lt;BR&gt;4C&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0047&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming live&lt;BR&gt;0E&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 004D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming dead&lt;BR&gt;30&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 004D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming dead&lt;BR&gt;F1 1B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0060&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EBX becoming dead&lt;BR&gt;38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0060&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDI becoming dead&lt;BR&gt;FF&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;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;Output of the command has 2 sections, the first part is method info block, which contains some basic information about the JITted code, like size of the method, size of the prolog, and etc. The 2&lt;SUP&gt;nd&lt;/SUP&gt; part is pointer table, on which I'll spend most of time. Pointer table describes lifetime of every GC reference inside the method. It has 3 columns, the first one is byte encodings, which we don't need to care about; the second column is the offset in the JITted code. E.g, this method's code starts from 02f00058, so 000B means the instruction at 02f00058+B = 2F00063, “xor&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ebx,ebx”;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;the third column tells us change of lifetime for&amp;nbsp;a GC pointer at that instruction. E,g, “000B&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;reg EDI becoming live” means starts from 2F00063, register EDI is a live root; similiarly, we can see EDI becomes dead at offset 60, end of the method (0060&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;reg EDI becoming dead). So whatever variable EDI is used to store, its lifetime is from beginning to end of the method. To understand the pointer table, it's better to interweave the table with the JITted code. In Whidbey, SOS has "!u -gcinfo" to do the job; but for Everett, I have to manually put them together and show it along with the source code:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;EM&gt;&amp;nbsp;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal dir=ltr&gt;02f00058 55&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp&lt;BR&gt;02f00059 8bec&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp,esp&lt;BR&gt;02f0005b 83ec08&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sub&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,0x8&lt;BR&gt;02f0005e 57&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02f0005f 56&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;BR&gt;02f00060 53&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx&lt;BR&gt;02f00061 33ff&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xor&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi,edi&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 000B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDI becoming live&lt;BR&gt;02f00063 33db&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xor&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx,ebx&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 000D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EBX becoming live&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;Test t = new Test (1);&amp;nbsp;&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;02f00065 b9e850ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad50e8 (MT: Test)&lt;BR&gt;02f0006a e8a91fbcfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0017&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming live&lt;BR&gt;02f0006f 8bf0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,eax&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0019&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming live&lt;BR&gt;02f00071 8bce&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,esi&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 001B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming live&lt;BR&gt;02f00073 ba01000000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edx,0x1&lt;BR&gt;02f00078 ff152051ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad5120] (Test..ctor)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0026&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming dead&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0026&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming dead&lt;BR&gt;02f0007e 8bfe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi,esi&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;BR&gt;&lt;EM&gt;ThreadProc tp = new ThreadProc (t.Reflect);&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;FONT size=4&gt;&lt;/FONT&gt;&lt;BR&gt;02f00080 b9c451ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad51c4 (MT: Test/ThreadProc)&lt;BR&gt;02f00085 e88e1fbcfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0032&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming live&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0032&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming dead&lt;BR&gt;02f0008a 8bf0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,eax&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0034&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming live&lt;BR&gt;02f0008c 689350ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; 0xad5093&lt;BR&gt;02f00091 8bd7&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edx,edi&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 003B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDX becoming live&lt;BR&gt;02f00093 8bce&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,esi&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 003D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming live&lt;BR&gt;02f00095 ff152452ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad5224] (Test/ThreadProc..ctor)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0043&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EAX becoming dead&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0043&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming dead&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0043&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDX becoming dead &lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;NewThread (tp); &lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;02f0009b 8bde&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx,esi&lt;BR&gt;02f0009d 8bcb&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,ebx&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0047&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming live&lt;BR&gt;02f0009f ff152c51ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad512c] (Test.NewThread)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 004D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ECX becoming dead&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 004D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg ESI becoming dead &lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;Thread.Sleep (1000); &lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;02f000a5 b9e8030000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0x3e8&lt;BR&gt;02f000aa ff155084bb79&amp;nbsp; call dword ptr [mscorlib_79990000+0x228450 (79bb8450)] (System.Threading.Thread.Sleep)&lt;BR&gt;02f000b0 90&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; nop&lt;BR&gt;02f000b1 5b&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebx&lt;BR&gt;02f000b2 5e&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;BR&gt;02f000b3 5f&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02f000b4 8be5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,ebp&lt;BR&gt;02f000b6 5d&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp&lt;BR&gt;02f000b7 c3&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; ret&lt;/P&gt;
&lt;P class=MsoNormal&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0060&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EBX becoming dead&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0060&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; reg EDI becoming dead&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;EM&gt;&amp;nbsp;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;Let's assume a thread triggers GC when another thread is excuting code 02f0009d. From the table, we know at this time, register ESI, EBX, and EDI will be reported as live roots to GC. With some disassembly, we could see at this moment both ESI and EBX contain reference to Delegate tp, and EDI is variable t. It might surprise you that both EBX and EDI keep alive until the function ends. That means variable t and tp are actually alive for the whole function, so the code has no bug?!&lt;/P&gt;
&lt;P class=MsoNormal&gt;The tricky point is that a variable is &lt;STRONG&gt;eligible&lt;/STRONG&gt; to be dead once it's not used anymore. However, it's up to JIT to determine whether it really wants to report the variable to be dead. In fact, for debuggable code, JIT extends lifetime for every variable to end of the function.&lt;/P&gt;
&lt;P class=MsoNormal&gt;To prove the premature GC bug really exists in the sample, I compiled it to "Release" build and repeated all the steps above:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;FONT face="Times New Roman" size=3&gt;0:000&amp;gt; !u 02df0058 &lt;BR&gt;Loaded Son of Strike data table version 5 from "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorwks.dll"&lt;BR&gt;Will print '&amp;gt;&amp;gt;&amp;gt; ' at address: 02df0058&lt;BR&gt;Normal JIT generated code&lt;BR&gt;[DEFAULT] Void Test.Main()&lt;BR&gt;Begin 02df0058, size 46&lt;BR&gt;&amp;gt;&amp;gt;&amp;gt; 02df0058 57&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02df0059 56&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;BR&gt;02df005a b9e850ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad50e8 (MT: Test)&lt;BR&gt;02df005f e8b41fcdfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;02df0064 8bf0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,eax&lt;BR&gt;02df0066 c7460401000000&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [esi+0x4],0x1&lt;BR&gt;02df006d b9bc51ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad51bc (MT: Test/ThreadProc)&lt;BR&gt;02df0072 e8a11fcdfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;02df0077 8bf8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi,eax&lt;BR&gt;02df0079 689350ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; 0xad5093&lt;BR&gt;02df007e 8bd6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edx,esi&lt;BR&gt;02df0080 8bcf&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,edi&lt;BR&gt;02df0082 ff151c52ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad521c] (Test/ThreadProc..ctor)&lt;BR&gt;02df0088 8bcf&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,edi&lt;BR&gt;02df008a ff152c51ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad512c] (Test.NewThread)&lt;BR&gt;02df0090 b9e8030000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0x3e8&lt;BR&gt;02df0095 ff155084bb79&amp;nbsp; call dword ptr [mscorlib_79990000+0x228450 (79bb8450)] (System.Threading.Thread.Sleep)&lt;BR&gt;02df009b 5e&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;BR&gt;02df009c 5f&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02df009d c3&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; ret&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;FONT face="Times New Roman" size=3&gt;0:000&amp;gt; !ip2md 02df0058 &lt;BR&gt;MethodDesc: 0x00ad50a8&lt;BR&gt;Jitted by normal JIT&lt;BR&gt;Method Name : [DEFAULT] Void Test.Main()&lt;BR&gt;MethodTable ad50e8&lt;BR&gt;Module: 151ad0&lt;BR&gt;mdToken: 06000003 (D:\projects\DelegateExample\bin\Release\DelegateExample.exe)&lt;BR&gt;Flags : 10&lt;BR&gt;Method VA : 02df0058 &lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;FONT face="Times New Roman" size=3&gt;0:000&amp;gt; !gcinfo 0x00ad50a8&lt;BR&gt;Normal JIT generated code&lt;BR&gt;Method info block:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; method&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; = 0046&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; prolog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 2 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 3 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; count&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 1 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&amp;nbsp;&amp;nbsp;&amp;nbsp; = yes &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; saved reg.&amp;nbsp; mask&amp;nbsp;&amp;nbsp; = 0003&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp frame&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; fully interruptible=no &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; double align&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; security check&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; exception handlers = no&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; local alloc&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; edit &amp;amp; continue&amp;nbsp;&amp;nbsp;&amp;nbsp; = no&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; varargs&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; argument&amp;nbsp;&amp;nbsp; count&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 0 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; stack frame size&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 0 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; untracked count&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;nbsp;&amp;nbsp; 0 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ptr tab count&amp;nbsp; =&amp;nbsp;&amp;nbsp; 0 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at&amp;nbsp;&amp;nbsp; 0043&lt;BR&gt;46 21&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |&amp;nbsp; &lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;FONT face="Times New Roman" size=3&gt;Pointer table:&lt;BR&gt;A9&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 001F&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call 0 [ ESI ]&lt;BR&gt;07&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0026&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&lt;BR&gt;CB&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | 0030&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call 1 [ EDI ]&lt;BR&gt;FF&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;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;Here is mixed source code, native code and pointer table:&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;02df0058 57&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02df0059 56&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; push&amp;nbsp;&amp;nbsp;&amp;nbsp; esi &lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;Test t = new Test (1); &lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;02df005a b9e850ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad50e8 (MT: Test)&lt;BR&gt;02df005f e8b41fcdfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;02df0064 8bf0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,eax&lt;BR&gt;02df0066 c7460401000000&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [esi+0x4],0x1 &lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;ThreadProc tp = new ThreadProc (t.Reflect); &lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;02df006d b9bc51ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0xad51bc (MT: Test/ThreadProc)&lt;BR&gt;02df0072 e8a11fcdfd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; 00ac2018 (JitHelp: nc)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 001F&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call 0 [ ESI ]&lt;BR&gt;02df0077 8bf8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi,eax&lt;BR&gt;02df0079 689350ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; 0xad5093&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0026&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&lt;BR&gt;02df007e 8bd6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edx,esi&lt;BR&gt;02df0080 8bcf&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,edi&lt;BR&gt;02df0082 ff151c52ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad521c] (Test/ThreadProc..ctor)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0030&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call 1 [ EDI ] &lt;/P&gt;
&lt;P class=MsoNormal&gt;EM&amp;gt;NewThread (tp);&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;02df0088 8bcf&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,edi&lt;BR&gt;02df008a ff152c51ad00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [00ad512c] (Test.NewThread) &lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;Thread.Sleep (1000);&lt;/EM&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;02df0090 b9e8030000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,0x3e8&lt;BR&gt;02df0095 ff155084bb79&amp;nbsp; call dword ptr [mscorlib_79990000+0x228450 (79bb8450)] (System.Threading.Thread.Sleep)&lt;BR&gt;02df009b 5e&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;BR&gt;02df009c 5f&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; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi&lt;BR&gt;02df009d c3&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; ret&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;In release build, the JIIted code is smaller, and the pointer table in GC info is much smaller. I need to explain some new syntax in this pointer table: “call 0 [ESI]” means the method calls a&amp;nbsp;function with 0 argument, and ESI is a live variable at this point; "push" just indicates change of the stack, which is important information for GC to unwind this frame, but doesn't affect pointer aliveness.&amp;nbsp;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;One thing interesting about this new pointer table is that it only reports GC references when the method calls into other methods. What if a GC happens somewhere else? For example, at line 02df0079, EDI contains object tp and ESI contains object t, if a GC happens while a thread is excuting 02df0079 but GCInfo doesn't report those two variables, will they be collected? The answer is GC can't happen at that place. There is an important field in method info block called "fully interruptable". In debug version, this field for the method is true but in release version the field is false. A method is fully interruptable means GC could stop a thread (and perform collection) at any point if the thread is executing this method. If a method is not fully interruptable, GC can't start at arbitrary point if a thread is executing this method. It has to wait until a point when the thread returns from a call (e.g, return from ThreadProc's constructor back to Main) or when the method calls into another method which allows GC to happen (calls into unmanaged code via PInvoke always allow GC to happen).&amp;nbsp;That's why we only need to report varaibles at calls.&amp;nbsp;For performance reason, such trivial methods like Test.Main is usually non-fully interruptable in release build.&lt;/P&gt;
&lt;P class=MsoNormal&gt;With all the knowledge, now we know that if a GC happens when a thread is just returning from the call "new ThreadProc" at instruction 02df0072, GC knows ESI (variable t) is a live root; if a GC happens when a thread is just returning from the call to ThreadProc's constructor at 02df0082, GC knows EDI (variable tp) is a live root. Variable t is not reported this time(but it's kept alive by object tp). However if a GC happens when a thread returns from the call to NewThread at 02df008a, neither t nor tp will be reported so they could be collected by GC. If the new thread hasn't start then, it will have trouble when using the objects.&lt;/P&gt;
&lt;P class=MsoNormal&gt;So next time if you suspect there might be some premature GC bug, you could try "!SOS.GCInfo" to see how exactly CLR thinks about the GC object's lifetime.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;EM&gt;&amp;nbsp;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;EM&gt;&amp;nbsp;&lt;/EM&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/o:p&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=417569" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>Thread safety of Timer callbacks</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2005/05/08/415480.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2005/05/08/415480.aspx</id><published>2005-05-08T11:12:00Z</published><updated>2005-05-08T11:12:00Z</updated><content type="html">&lt;P class=MsoNormal&gt;I didn't realize I've stopped blogging for 1 year. What a shame! Fortunately I didn’t waste the time: we ship Whidbey Beta1 and Beta2 in the past year! Now with Beta2 out of door, I have more spare time for blogging. :)&lt;/P&gt;&lt;BR&gt;
&lt;P class=MsoNormal&gt;Today I want to talk about some interesting facts about Timer in CLR. There is an example for how to use timer in MSDN:&amp;nbsp;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemthreadingtimerclasstopic.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemthreadingtimerclasstopic.asp&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;/P&gt;&lt;BR&gt;
&lt;P class=MsoNormal&gt;This sample starts a timer and does certain things when the timer fires for certain times, like killing the timer. However, this sample has a bug which will cause trouble in stress scenario. To demonstrate the problem, I made a little change to the code:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;using System;&lt;BR&gt;using System.Threading;&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;class TimerExample&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;static void Main()&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;AutoResetEvent autoEvent&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = new AutoResetEvent(false);&lt;BR&gt;&amp;nbsp;&amp;nbsp;StatusChecker&amp;nbsp; statusChecker = new StatusChecker(100);&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;// Create the delegate that invokes methods for the timer.&lt;BR&gt;&amp;nbsp;&amp;nbsp;TimerCallback timerDelegate = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;new TimerCallback(statusChecker.CheckStatus);&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;Console.WriteLine("{0} Creating timer.\n", &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;DateTime.Now.ToString("h:mm:ss.fff"));&lt;BR&gt;&amp;nbsp;&amp;nbsp;Timer stateTimer = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;new Timer(timerDelegate, autoEvent, 0, 10);&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;// start another thread to post work items to thread pool&lt;BR&gt;&amp;nbsp;&amp;nbsp;Thread t = new Thread (new ThreadStart (PostWortItem));&lt;BR&gt;&amp;nbsp;&amp;nbsp;t.Start ();&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;// When autoEvent signals, dispose of &lt;BR&gt;&amp;nbsp;&amp;nbsp;// the timer.&lt;BR&gt;&amp;nbsp;&amp;nbsp;autoEvent.WaitOne();&lt;BR&gt;&amp;nbsp;&amp;nbsp;stateTimer.Dispose();&lt;BR&gt;&amp;nbsp;&amp;nbsp;Console.WriteLine("\nDestroying timer.");&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;// a Thread proc which keeps posting work items to thread pool&lt;BR&gt;&amp;nbsp;static void PostWortItem ()&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;// Post some user work items to thread pool&lt;BR&gt;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; 1000; i++)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ThreadPool.QueueUserWorkItem (new WaitCallback (WorkItem));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.Sleep (10);&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;// An nop work item for thread pool&lt;BR&gt;&amp;nbsp;static void WorkItem (object o)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;Thread.Sleep (500);&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;class StatusChecker&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;int invokeCount, maxCount;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;public StatusChecker(int count)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;invokeCount&amp;nbsp; = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;maxCount = count;&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;// This method is called by the timer delegate.&lt;BR&gt;&amp;nbsp;public void CheckStatus(Object stateInfo)&lt;BR&gt;&amp;nbsp;{&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;Console.WriteLine("Checking status " + (++invokeCount));&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;if(invokeCount == maxCount)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//signal Main.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;autoEvent.Set();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;}&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;Basically I added another thread to keep posting work items to threadpool, but the rest part is still expected to behave the same: when the timer fires the 100&lt;SUP&gt;th&lt;/SUP&gt; time, it should set an event so the main thread would stop the timer.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;In one of 5 runs in my machine, I got such output:&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;FONT size=2&gt;5:48:07.625 Creating timer.&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;FONT size=2&gt;Checking status 1&lt;BR&gt;Checking status 2&lt;BR&gt;Checking status 3&lt;BR&gt;Checking status 4&lt;BR&gt;…&lt;BR&gt;Checking Status 93&lt;BR&gt;Checking Status 94&lt;BR&gt;Checking Status 95&lt;BR&gt;Checking Status 96&lt;BR&gt;Checking Status 97&lt;BR&gt;Checking Status 98&lt;BR&gt;Checking Status 102&lt;BR&gt;Checking Status 99&lt;BR&gt;Checking Status 103&lt;BR&gt;Checking Status 104&lt;BR&gt;Checking Status 105&lt;BR&gt;…&lt;BR&gt;Checking Status 698&lt;BR&gt;Checking Status 700&lt;BR&gt;Checking Status 701&lt;BR&gt;Checking Status 703&lt;BR&gt;Checking Status 703&lt;BR&gt;Checking Status 704&lt;BR&gt;Checking Status 705&lt;BR&gt;…&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;FONT size=2&gt;^C&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal dir=ltr&gt;It seems that &lt;SPAN&gt;&lt;EM&gt;invokeCount&lt;/EM&gt; &lt;/SPAN&gt;never hits 100 thus the program doesn't stop and some other sequence in the output looks to be out of order.&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;How does this happen? First we need to understand how timer is implemented in CLR, who is executing the timer callbacks?&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;One simple idea would be putting all timers in a queue and having a dedicate thread doing something like this (pseudo code):&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;&lt;EM&gt;&lt;FONT size=2&gt;&lt;o:p&gt;while (true)&lt;BR&gt;{&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach (Timer t in timer queue)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (t.TimeToFire ())&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&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;t.InvokeCallback ();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Sleep(MinumInterval);&lt;BR&gt;}&lt;/o:p&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;However with this logic one lengthy timer callback would block all other timers. In CLR, we do have a timer queue and a dedicate timer thread. However the only job of timer thread is to maintain the timer queue, when a timer needs to fire, timer thread queue a work item to threadpool, then a thread pool's worker thread will pick up the work item and invoke the timer callback.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;In Rotor's source, the timer thread's logic is in &lt;I&gt;vm/Win32threadpool.cpp&lt;/I&gt;, the thread proc is &lt;I&gt;&lt;SPAN&gt;ThreadpoolMgr::TimerThreadStart&lt;/SPAN&gt;&lt;/I&gt; and &lt;I&gt;&lt;SPAN&gt;ThreadpoolMgr::FireTimers&lt;/SPAN&gt;&lt;/I&gt; does most of interesting work. The pseudo code looks like:&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;while (true)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach (Timer t in timer queue)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (t.TimeToFire ())&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// put a work item to thread pool&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// to call timer cal back on t once&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WorkItem work = CallTimerCallbackOnce (t);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ThreadPool.QueueWorkItem (work);&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;//MinumInterval is minum of next firing interval&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// for all timers in the queue&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Sleep(MinumInterval);&lt;BR&gt;}&lt;/FONT&gt;&lt;/EM&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;The timer thread only guarantees to put timer callback requests to a queue in thread pool (&lt;I&gt;&lt;SPAN&gt;ThreadpoolMgr::QueueUserWorkItem&lt;/SPAN&gt;&lt;/I&gt;) in order of timer firing. But timer callbacks are not called in a serialized way. If a timer fires twice and there are more than one worker thread in thread pool, there's no guarantee that the first callback will be finished before the next callback starts. Therefore, it's not thread safe for timer callbacks to access shared data without locking. That's why the example in MSDN breaks:&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;when &lt;I&gt;&lt;SPAN&gt;CheckStatus&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; &lt;/SPAN&gt;is executed in multiple threads, it's possible that "&lt;I&gt;&lt;SPAN&gt;if&lt;/SPAN&gt;&lt;/I&gt;&lt;I&gt;&lt;SPAN&gt;(invokeCount == maxCount)"&lt;/SPAN&gt;&lt;/I&gt;&amp;nbsp; will never be satisfied. Changing the code to this would make it more robust:&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;public void CheckStatus(Object stateInfo)&lt;BR&gt;{&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;int count = Interlocked.Increment (ref invokeCount);&lt;BR&gt;&amp;nbsp;&amp;nbsp;Console.WriteLine("Checking status " + count);&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&lt;EM&gt;&lt;FONT size=2&gt;&amp;nbsp;&amp;nbsp;if(count == maxCount)&lt;BR&gt;&amp;nbsp;&amp;nbsp;…&amp;nbsp;&lt;/FONT&gt;&lt;/EM&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoNormal&gt;Another interesting thing about timer implementation is that when a client thread creates a new timer, it doesn't insert the timer to timer queue directly. Instead, it queues a user APC to the timer thread (see &lt;I&gt;&lt;SPAN&gt;ThreadpoolMgr::CreateTimerQueueTimer&lt;/SPAN&gt;&lt;/I&gt; and &lt;I&gt;&lt;SPAN&gt;InsertNewTimer&lt;/SPAN&gt;&lt;/I&gt;). Similar thing is done for updating (&lt;I&gt;&lt;SPAN&gt;ThreadpoolMgr::ChangeTimerQueueTimer&lt;/SPAN&gt;&lt;/I&gt; and &lt;I&gt;&lt;SPAN&gt;UpdateTimer&lt;/SPAN&gt;&lt;/I&gt;) and deleting timer (&lt;I&gt;&lt;SPAN&gt;ThreadpoolMgr:: DeleteTimerQueueTimer&lt;/SPAN&gt;&lt;/I&gt; and &lt;I&gt;&lt;SPAN&gt;DeregisterTimer&lt;/SPAN&gt;&lt;/I&gt;). That way, client threads don't need to synchronize to access the shared timer queue. After all, the timer thread is sleeping (alertable) for most of time. &lt;/P&gt;&lt;BR&gt;PS: to make the race happen more easily, I did more tweaks to the MSDN sample than the threadpool workitems, it should be obvious to you. ;) &lt;BR&gt;&lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=415480" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="Rotor code explanation" scheme="http://blogs.msdn.com/yunjin/archive/tags/Rotor+code+explanation/default.aspx" /><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>How handy auto-boxing could be!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2004/06/05/149361.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2004/06/05/149361.aspx</id><published>2004-06-06T00:30:00Z</published><updated>2004-06-06T00:30:00Z</updated><content type="html">&lt;P&gt;I've been quiet for 3 months and probably won't&amp;nbsp;have much&amp;nbsp;time for blogs for next several months down the road. Today I got a chance to update&amp;nbsp;my post &lt;A id=viewpost.ascx_TitleUrl HREF="/yunjin/archive/2004/01/27/63642.aspx"&gt;&lt;FONT color=#0000ff&gt;OutOfMemoryException and Pinning&lt;/FONT&gt;&lt;/A&gt;&amp;nbsp;to correct a mistake pointed out by our GC architect Patrick Dussud. Also I want to remind everyone that Michael Stanton posted a great &lt;A href="http://blogs.msdn.com/mvstanton/archive/2004/04/05/108023.aspx"&gt;article&lt;/A&gt; in April about how to traverse the GC heap using psscor.dll. This technique is quite useful to understand the internal of CLR's GC. Talking about GC heap, I want to tell another GC heap corruption story.&lt;/P&gt;
&lt;P&gt;My test buddy Chris Lyon debugged a customer program with me recently and found a very interesting user bug. He already posted the problem in an internal blog, I think it's worthy&amp;nbsp;to share it with the public community too. The problem is in this code:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;SomeStruct[] arr = new SomeStruct[SomeSize];&lt;BR&gt;GCHandle handle = GCHandle.Alloc(Marshal.SizeOf(typeof(SomeStruct)) * SomeSize, GCHandleType.Pinned); &lt;BR&gt;IntPtr fixedAddr = handle.AddrOfPinnedObject ();&lt;BR&gt;... //pass fixedAddr to unmanaged code to filled the array&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This code tries to&amp;nbsp;create a pinned GC handle for an array then pass the array's address to unmanaged code to fill in. The code seems to assume &lt;EM&gt;GCHandle.Alloc &lt;/EM&gt;has similiar semantics as &lt;EM&gt;malloc&lt;/EM&gt; - tell it how much memory we need and it will allocate it for us. But it's not true. &lt;EM&gt;GCHandle.Alloc&lt;/EM&gt; only allocates a (pointer-sized) GC handle&amp;nbsp;for a given object without allocating memory for the object. The first argument for this method is supposed to be the &lt;EM&gt;Object &lt;/EM&gt;which&amp;nbsp;the handle will&amp;nbsp;point to. This program passes an &lt;EM&gt;Int32&lt;/EM&gt; (size of the array)&amp;nbsp;to the method, but the compiler won't give us any error because the nice handy auto-boxing feature. At runtime what would happen is CLR will&amp;nbsp;box the integer to be&amp;nbsp;a heap object, allocate a pinned handle for this integer object, then address of this object will be passed to unmanaged code. The unmanaged code will copy SomeSize * sizeof(SomeStruct) byte data to the 4 byte integer and overwrites other objects in the heap. We could just relax and wait the program to crash.&lt;/P&gt;
&lt;P&gt;This example looks quite trivial, but it demos how easy GC heap could be corrupted by user error with help of unmanaged code. One suggestion: watch out any IntPtr you passed to unmanaged code!&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=149361" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /></entry><entry><title>Dangerous PInvokes - string modification</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2004/02/21/77744.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2004/02/21/77744.aspx</id><published>2004-02-22T02:30:00Z</published><updated>2004-02-22T02:30:00Z</updated><content type="html">&lt;P class=MsoNormal&gt;Objects in CLR are usually managed by the runtime in GC heap; user code does not have direct access to the objects. CLR's reliability and type safety heavily rely on this fact. But CLR also support InterOp features like COM InterOp, IJW and PInvoke to allow unmanaged code to touch managed objects directly. It's very dangerous to use those InterOp techniques without caution. The potential problems include:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI class=MsoNormal&gt;Security. Unmanaged code could bypass the runtime to access any controlled resources and change any state of a managed program. That's why calling unmanaged code requires very high security permission. 
&lt;LI class=MsoNormal&gt;Reliability. Unmanaged code could access managed objects (thus GC heap) directly. So it could corrupt GC heap easily, which is fatal error for CLR. Ideally, in a pure managed world, all&amp;nbsp;bugs in user code&amp;nbsp;should result in an exception or error code; but with mistakes in an InterOp operation, you could find the program just crashes with no clues. Because the corruption happens deeply in CLR, the problem would be very hard to debug for users.&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;InterOp is quite a complicated topic, so it's better for programmers to have deep understanding before writing such code. I would highly recommend &lt;a href="https://blogs.msdn.com:443/adam_nathan/"&gt;Adam Nathan&lt;/A&gt;'s book &lt;A href="http://www.amazon.com/exec/obidos/tg/detail/-/067232170X/002-3436211-1718438?v=glance"&gt;“.NET and COM – The Complete Interoperability Guide&lt;/A&gt;”, which is the bible of CLR InterOp.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;Among the three basic InterOp techs, PInvoke seems to be much simpler than the other two. Most time it requires&amp;nbsp;only declaring and calling, like using any managed functions. But I want to remind people some catch-chas of PInvokes. Because:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI class=MsoNormal&gt;PInvoke calls into pure unmanaged DLL, which has almost no self-description data for CLR. So there's not much validation CLR could perform at compile and run time. (Performance is another reason for little validation at run time) 
&lt;LI class=MsoNormal&gt;It's so easy to use, sometimes people forget the danger built-in its unmanaged nature. :)&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;The first topic I want to cover is string's immutability in PInvoke. In &lt;a href="https://blogs.msdn.com:443/cbrumme/archive/2003/04/22/51371.aspx"&gt;one of his wonder blogs&lt;/A&gt;, &lt;a href="https://blogs.msdn.com:443/cbrumme/"&gt;Chris Brumme&lt;/A&gt; talked about why immutability is important for strings, especially interned strings. He gave an example about how a string's contents could be changed in place with a PInvoke call:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;using System;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;using System.Runtime.InteropServices;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;public class Class1&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;static void Main(string[] args)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&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&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;String computerName = "strings are always immutable";&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;String otherString = "strings are always immutable";&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;int len = computerName.Length;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;GetComputerName(computerName, ref len);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Console.WriteLine(otherString);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&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&gt;&lt;SPAN&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;[DllImport("kernel32", CharSet=CharSet.Unicode)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;static extern bool GetComputerName(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;[MarshalAs (UnmanagedType.LPWStr)] string name,&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ref int len);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;This example demos that when you change contents of one interned string, another string might be changed unintentionally. I want to add one more point: &lt;STRONG&gt;string's hash code is calculated using its contents, so changing a string's contents would change its hash code, which violates the invariant that an object's hash code should not change over its lifetime&lt;/STRONG&gt;. It's very hard to know if the string you are modifying is used as a hash key anywhere in CLR or user's code. As a matter of fact, in V1.0 and V1.1 CLR stores all interned strings in a hash table across AppDomains. So if an interned string's contents&amp;nbsp;are changed, it could mess up the underlying hash table, and cause CLR to crash mysteriously&amp;nbsp;during later AppDomain loading/unloading.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;As mentioned in Chris's blog and Adam's book, the solution is to declare&amp;nbsp;a PInvoke to use StringBuilder for any string parameters it might modify. A common pitfall here is that people might believe if an unmanaged function requires a LPTSTR as a parameter, the interface should be declared&amp;nbsp;to use&amp;nbsp;StringBuilder in managed code; if it's a LPCTSTR (or any other constant character pointer), it's safe to be declared as a String. This is not 100% correct because unmanaged code could always cast a constant pointer to be a mutable one. For example, Windows GDI's DrawText API is declared as:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;int DrawText(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;HDC &lt;SPAN&gt;hDC&lt;/SPAN&gt;,&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;// handle to DC&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;LPCTSTR &lt;SPAN&gt;lpString&lt;/SPAN&gt;, // text to draw&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;int &lt;SPAN&gt;nCount&lt;/SPAN&gt;,&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;// text length&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;LPRECT &lt;SPAN&gt;lpRect&lt;/SPAN&gt;,&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;// formatting dimensions&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;UINT &lt;SPAN&gt;uFormat&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;// text-drawing options&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;The lpString here looks to be constant, but description of MSDN says:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;lpString &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;[in] Pointer to the string that specifies the text to be drawn. If the nCount parameter is –1, the string must be null-terminated. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;STRONG&gt;If uFormat includes DT_MODIFYSTRING, the function could add up to four additional characters to this string.&lt;/STRONG&gt; The buffer containing the string should be large enough to accommodate these extra characters. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;In Appendices E of his book, Adam suggests managed declaration of this function could be:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;[DllImport (“User32”, CharSet=Charset.Auto)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;static extern in DrawText (IntPtr hDC, string lpString, int nCount, ref RECT lpRect, uint uFormat);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;This is right for most of time, but such a usage could cause problem:&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;string text = "Hello world!";&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;DrawText (hDC, text, text.Length, ref rect, DT_END_ELLIPSIS | DT_MODIFYSTRING);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;If the function tries to append some additional characters to the string, it will write out of range of this string object and overwrite other objects in the managed heap, which would corrupt the heap and might crash CLR eventually.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;The point I want to make is that PInvoke might look simple, but it's still dangerous (because all unmanaged code is dangerous for CLR :)). Now CLR can't&amp;nbsp;check correctness of a PInovke signature automatically. Instead, we have some run time debugging tools like CDPs for some particular checking around PInvoke. Adam's blogs has very good coverage on them. In the long run we may be able to do some analysis using static tools but there's no specific plan at this time. So to avoid any PInvoke problem, users need to understand it very well and read the documents of the unmanaged function carefully. If you are experiencing any unexplainable crash in a .NET program, it might be worthy to check all the PInvokes in the code.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=77744" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>FCall and GC hole - first post about Rotor</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2004/02/08/69906.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2004/02/08/69906.aspx</id><published>2004-02-09T09:34:00Z</published><updated>2004-02-09T09:34:00Z</updated><content type="html">&lt;P&gt;&lt;STRONG&gt;&lt;SPAN&gt;An exsample of FCall&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;My friend &lt;a href="https://blogs.msdn.com:443/joelpob"&gt;Joel Pobar&lt;/A&gt; had a great &lt;a href="https://blogs.msdn.com:443/joelpob/archive/2003/12/18/53745.aspx"&gt;post&lt;/A&gt; to demo how to add new code to Rotor&amp;nbsp;which exposes more&amp;nbsp;EE(Execution Engine)&amp;nbsp;internal information to managed world. This is a very good example covers both BCL and EE, and how the two parts interact with each other. As showed in this example, BCL code could call into EE by a special&amp;nbsp;type of method called “FCall“, like this:&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;FCIMPL1(MethodBody *, COMMember::GetMethodBody, MethodDesc **ppMethod)&lt;/SPAN&gt;&lt;/EM&gt;&lt;I&gt;&lt;SPAN&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;{ &lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; MethodDesc* pMethod = *ppMethod;&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; METHODBODYREF MethodBodyObj = NULL;&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; HELPER_METHOD_FRAME_BEGIN_RET_0();&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; GCPROTECT_BEGIN(MethodBodyObj);&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; TypeHandle thMethodBody(g_Mscorlib.FetchClass(CLASS__METHOD_BODY));&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; MethodBodyObj = (METHODBODYREF)AllocateObject(thMethodBody.GetMethodTable());&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; Module* pModule = pMethod-&amp;gt;GetModule();&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; COR_ILMETHOD_DECODER MethodILHeader(pMethod-&amp;gt;GetILHeader(), pModule-&amp;gt;GetMDImport(), TRUE);&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; MethodBodyObj-&amp;gt;maxStackSize = MethodILHeader.GetMaxStack();&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; GCPROTECT_END();&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; HELPER_METHOD_POLL();&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; HELPER_METHOD_FRAME_END();&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; &lt;SPAN&gt;&lt;FONT color=#000000&gt;return&lt;/FONT&gt;&lt;/SPAN&gt; (MethodBody*)OBJECTREFToObject(MethodBodyObj);&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;FCIMPLEND &lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;SPAN&gt;As I said before I'd try to&amp;nbsp;explain some Rotor code in my blog, so let me start by analyzing a small problem in&amp;nbsp;that piece of&amp;nbsp;code. I won't call it a bug because it happens to be harmless here. But it does violate some CLR coding rules.&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN&gt;Some basic bricks of an FCall&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;First let's take a glance of those&amp;nbsp;amazing&amp;nbsp;macros:&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI class=MsoNormal&gt;FCIMPL1/FCIMPLEND: defined in vm/fcall.h. They just tweak calling convention between managed code (BCL)&amp;nbsp;and unmanaged code (EE). You can see different flavors of FCIMPL, which serve calls with different argument numbers or types (to match the argument passing and enregistering rules in managed world).&lt;o:p&gt;&lt;/o:p&gt; 
&lt;LI class=MsoNormal&gt;HELPER_METHOD_FRAME_BEGIN_RET_0/HELPER_METHOD_FRAME_END: defined in vm/fcall.h. For operations like GC (Garbage Collection) and EH (Exception Handling) to work correctly, some frames have to be set up in the stack, especially&amp;nbsp;at the boundary&amp;nbsp;between managed part and unmanaged part. Frames are a topic could take a blog entry itself, so I won't cover it too much here. What you need to know now is that for performance reason, an FCall doesn't set up a frame by default. So when an FCall wants to throw an exception or allow a GC to happen, it has to set up a HelperMethodFrame (vm/frames.h)&amp;nbsp;first. This job is done by HELPER_METHOD_FRAME_BEGIN* macro.HELPER_METHOD_FRAME_END is to tear down the frame from stack. All GC or exception throwing has to happen in the range guarded by this frame. In the code above, some operations&amp;nbsp;could trigger a GC (at least AllocateObject could do so, not sure about others. It would be a hard job to trace into each code path to find out whether a GC could happen), so a HelperMethodFrame has to be established before&amp;nbsp;that call.&amp;nbsp;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt; 
&lt;LI class=MsoNormal&gt;GCPROTECT_BEGIN/GCPROTECT_END: defined in vm/frames.h. Similar to HELPER_METHOD_FRAME_BEGIN*, GCPROTECT_BEGIN is used to set up a GCFrame (vm/frames.h)&amp;nbsp;and GCPROTECT_END pop the frame out.&amp;nbsp;When a GC happens, it needs to find out all object references in stack to trace which objects in the managed heap are still alive, and when it moves the object (to compact the heap) it needs to update the references in stack with the new location of the objects. For managed code, JIT&amp;nbsp;generates all&amp;nbsp;information&amp;nbsp;needed by GC. But for unmanaged part of CLR, the code whoever has references to managed objects is responsible&amp;nbsp;to report all references itself. A GCFrame serves for this purpose. If an unmanaged method pushes a GCFrame to stack, the frame will report the protected reference&amp;nbsp;(the argument to GCPROTECT_BEGIN) during GC.&amp;nbsp;In our example, MethodBodyObj&amp;nbsp;is an object&amp;nbsp;reference so we set up a GCFrame for it. 
&lt;LI class=MsoNormal&gt;HELPER_METHOD_POLL: defined in vm/fcall.h. This macro is meant to do a GC poll in range of a HelperMethodFrame. GC poll is another complicated thing I don't want to talk here. Basically it allows GC to happen in another thread, without a poll another thread&amp;nbsp;that wants to perform a GC might be blocked, thus all managed threads in the application will be blocked.&lt;o:p&gt;&lt;/o:p&gt; 
&lt;LI class=MsoNormal&gt;OBJECTREFToObject: defined in vm/vars.hpp. It's used to take a pure object pointer out from an ObjectRef. An ObjectRef is a naked pointer in free build, but a wrapper with some very useful checking in debug build.&lt;o:p&gt;&lt;/o:p&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;The problem&lt;/STRONG&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;1. GC hole. In COMMember::GetMethodBody, a HELPER_METHOD_POLL is put after GCPROTECT_END. As I explained above, GCPROTECT_END will pop up the GC frame which is protecting the object reference, but HELPER_METHOD_POLL allows a GC to happen in another thread. So there are chances&amp;nbsp;(although very small) that after the GC frame is popped up, another thread performs a GC. In such a GC, MethodBodyObj won't be reported. So GC might not know the object referenced by&amp;nbsp;MethodBodyObj is still alive (if there's no other reference&amp;nbsp;to the object)&amp;nbsp;and collect it; or (if there are other references) GC might move the object but not update MethodBodyObj with the new address thus MethodBodyObj would hold a “stale” object pointer. Either case, COMMember::GetMethodBody will return a bogus object and the program might crash later in an unexpected way. We call this kind of errors “GC holes” in CLR.&amp;nbsp;They are hard to detect because GC is non-deterministic.&amp;nbsp;The funny thing is that nothing bad would happen in this method because HELPER_METHOD_POLL is actually defined as a no-op in this version:&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;// This is the fastest way to do a GC poll if you have already erected a HelperMethodFrame&lt;/SPAN&gt;&lt;/EM&gt;&lt;I&gt;&lt;SPAN&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;// #define HELPER_METHOD_POLL()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { __helperframe.Poll(); INDEBUG(__fCallCheck.SetDidPoll()); }&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;#define HELPER_METHOD_POLL()&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;/SPAN&gt;&lt;/EM&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I don't know why we&amp;nbsp;use an empty macro for HELPER_METHOD_POLL but I'm sure it's&amp;nbsp;supposed to be the version which is commented out. In later versions we may uncomment the above line to make HELPER_METHOD_POLL take effect. So although this FCall doesn't cause any trouble for now, it might later. The corrected version should be:&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;HELPER_METHOD_FRAME_BEGIN_RET_0();&lt;/SPAN&gt;&lt;/EM&gt;&lt;I&gt;&lt;SPAN&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;GCPROTECT_BEGIN(MethodBodyObj);&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;HELPER_METHOD_POLL();&lt;/SPAN&gt;&lt;/EM&gt;&lt;I&gt;&lt;SPAN&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;GCPROTECT_END();&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;HELPER_METHOD_FRAME_END();&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;2.&amp;nbsp;If you&amp;nbsp;dig deep into the code of&amp;nbsp; HELPER_METHOD_FRAME_BEGIN*, you will find that those macros do a GC poll themselves. So unless the FCall does some very time consuming work, there's no need for another poll.&amp;nbsp;Thus a&amp;nbsp;refined version of&amp;nbsp;our sample&amp;nbsp;would be:&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;HELPER_METHOD_FRAME_BEGIN_RET_0();&lt;/SPAN&gt;&lt;/EM&gt;&lt;I&gt;&lt;SPAN&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;GCPROTECT_BEGIN(MethodBodyObj);&lt;/SPAN&gt;&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;GCPROTECT_END();&lt;/SPAN&gt;&lt;/EM&gt;&lt;I&gt;&lt;SPAN&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;HELPER_METHOD_FRAME_END();&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;3. Because setting up HelperMethodFrame usually means the code wants to allow GC,&amp;nbsp;for convenience we have&amp;nbsp;versions of HELPER_METHOD_FRAME_BEGIN* to protect&amp;nbsp;object references.&amp;nbsp;Then&amp;nbsp;a GCFrame is not needed. So the FCall could be written this way:&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;HELPER_METHOD_FRAME_BEGIN_RET_1(MethodBodyObj);&lt;/SPAN&gt;&lt;/EM&gt;&lt;I&gt;&lt;SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;SPAN&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN&gt;HELPER_METHOD_FRAME_END();&lt;/SPAN&gt;&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I hope you already got a taste how FCall works in CLR by reading this blog. Actually most thing I talked here can be found in comments at the beginning of vm/fcall.h. And if you want to see more examples of FCall, just search FCIMPL in vm directory, you will get plenty of them. Then you will see how CLR build a&amp;nbsp;beautiful&amp;nbsp;object-oriented world&amp;nbsp;by the old fashion and kinda dirty way.&lt;SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=69906" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term="Rotor code explanation" scheme="http://blogs.msdn.com/yunjin/archive/tags/Rotor+code+explanation/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry><entry><title>ExitThread() in managed program?</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2004/01/30/65386.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2004/01/30/65386.aspx</id><published>2004-01-31T02:37:00Z</published><updated>2004-01-31T02:37:00Z</updated><content type="html">&lt;P&gt;I've seen people calls OS's ExitThread in managed applications via PInvoke to exit a managed thread, like this:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;EM&gt;[DllImport( "Kernel32.dll")]&lt;BR&gt;public static extern void ExitThread(int exitCode);&lt;/EM&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;EM&gt;public static void Run ()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // calling OS's ExitThread to exit the current thread&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExitThread (0);&lt;BR&gt;}&lt;/EM&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;EM&gt;public static void Main () &lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ThreadStart threadStart = new ThreadStart(Run);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread thread = new Thread(threadStart);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; thread.Start();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;BR&gt;}&lt;/EM&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I&amp;nbsp;guess&amp;nbsp;when unmanaged code is ported to managed code,&amp;nbsp;people tends to&amp;nbsp;translate every system call to a PInvoke. But&amp;nbsp;because CLR provides another layer over the OS, some low level system calls don't make sense in&amp;nbsp;the managed world.&amp;nbsp;ExitThread is one of them, because managed threads&amp;nbsp;are not equivlent to OS's native threads. The above code is wrong for 2 reasons:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;CLR has some clean up work (like stack unwinding) to do when a managed thread exits. CLR knows a managed thread is exiting when the thread procedure (like threadStart)&amp;nbsp;returns or a ThreadAbortException is thrown. Calling OS's ExitThread (or even worse, TerminateThread) would bypass all back out code on the stack (such as destructor and finally block) and leave the program in an unspecified state. 
&lt;LI&gt;There is no guarantee about how CLR maps a managed/logical thread to an OS/physical thread. For example, several managed threads could be mapped to one OS thread, calling ExitThread in one managed thread might kill other managed threads unintentionally.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;IMHO, calling system's ExitThread in managed program is almost always a mistake. Instead, we could just call Thread.Abort.&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=65386" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /></entry><entry><title>OutOfMemoryException and Pinning</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx" /><id>http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx</id><published>2004-01-28T06:52:00Z</published><updated>2004-01-28T06:52:00Z</updated><content type="html">&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;As you all know, in CLR memory management is done by Garbage collector (GC). When GC can't find memory in preallocated memory chunk (GC heap) for new objects and can't book enough memory from the OS to expand GC heap, it throws OutOfMemoryException (OOM).&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;o:p&gt;&lt;FONT face="Courier New" size=2&gt;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;The problem&lt;o:p&gt;&lt;/o:p&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;From time to time, I've heard complaints about OOM - people analyze code and monitor memory usage, find out that sometimes their .NET applications throw OOM when there's enough free memory. In most cases I've seen, the problems are:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;The virtual address space of the OS is fragmented. This is usually caused by some unmanaged components in the application. This issue exists in unmanaged world for long time, but it could hit GC hard. GC heap is managed in unit of segments, whose size is 16MB for workstation version and 32MB for server version in V1.0 and V1.1. That means when CLR needs to expand GC heap, it has to find 32MB consecutive free virtual memory for a server application. Usually this is not a problem in a system with 2GB address space for user mode. But if there are some unmanaged DLLs in the application manipulating virtual memory without carefulness, the virtual address space could be divided into small blocks of free and reserved memory. Thus GC would fail to find a big enough piece of free memory although the total free memory is enough. This kind of problems could be found out by looking through the whole virtual address space to see which block is reserved by which component.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;The GC heap itself is fragmented, meaning GC can't allocate objects in already reserved segments which actually have enough free space inside. I want to focus on this problem in this blog.&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;A glance of GC heap&lt;o:p&gt;&lt;/o:p&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Usually managed heap shouldn't suffer from fragmentation problem because the heap is compacted during GC. Blow shows an oversimplified model of CLR's GC heap:&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;All objects are adjacent to each other; the top of heap is free space.&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;|---------|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |free&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object B |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;New objects are allocated in free space. Allocation always happens at top, just as a stack.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|---------|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;|free&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object C |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object B |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;When free space is used up, a GC happens. During GC, reachable objects are marked.&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |---------|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object C | (marked)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object B |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A | (marked) &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;After GC, heap is compacted, live (reachable) objects are relocated, dead (unreachable) objects are swept out.&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |---------|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |free&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object C |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face="Courier New"&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;Free space in GC heap&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;In above model, you can see that GC actually does a good job to defragment the heap. Free space is always at top of the heap and available for new allocation. But in real production, free space could reside among allocated objects. That is because:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Sometimes GC could choose not to compact part of the heap when it's not necessary. Since relocating all objects could be expensive, GC might avoid doing so under some conditions. In that case, GC will keep a list of free space in heap for future compaction. This won't cause heap fragmentation because GC has full control over the free space. GC could fill up those blocks anytime later when necessary.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Pinned objects are not movable. So if a pinned object survives a GC, it could create a block of free space, like this:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;before GC:&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;&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; after GC:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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;&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;&amp;nbsp; |---------|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object C | (pinned, reachable)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Object C | (pinned)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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;&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;&amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object B | (unreachable)&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; | free&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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;&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;&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;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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;&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;&amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A | (reachable)&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; |Object A |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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;&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;&amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face="Courier New"&gt;&lt;o:p&gt;&lt;STRONG&gt;How pinning could fragment GC heap&lt;/STRONG&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;if an application keeps pinning objects in this pattern: pin a new object, do some allocation, pin another object, do some allocation ... and all pinned objects remain pinned for long time, a lot of free space will be created, showed below:&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;A new object is pinned&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |---------|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |free&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned 1 |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;After some allocation, another object is pinned&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |---------|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |free&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned 2 |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned 1 |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;More objects are pinned, with unpinned objects in between&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned n |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned 2 |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned 1 |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Object A |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;A GC happens, because pinned objects can't be relocated, free space remains in the heap&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned n |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; | free&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned 2 |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; | free&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |Pinned 1 |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; | free&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |_________|&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp; ...&amp;nbsp;&amp;nbsp; |&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Such a process could create a GC heap with a lot of free slots. Those free slots are being partially reused for allocation but when they are too small or when their remainder is too small,&amp;nbsp;GC can’t use them as long as the objects are pinned. This would prevent GC from using the heap efficiently and might cause OOM eventually.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;One thing makes the situation worse is that although a developer may not use pinned objects directly, some .Net libraries use them under the hood, like asynchronized IO. For example, in V1.0 and V1.1 the buffer passed to Socket.BeginReceive is pinned by the library so that unmanaged code could access the buffer. Consider a socket server application which handles thousands of socket requests per second and each request could take several minutes because of slow connection, GC heap could be fragmented a lot because of large amount of pinned objects and long lifetime some objects are pinned; then OOM could happen.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;How to diagnose the problem&lt;o:p&gt;&lt;/o:p&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;To determine if GC heap is fragmented, SOS is the best tool. Sos.dll is a debugger extension shipped with .NET framework which could check some underlying data structure in CLR. For example, “DumpHeap” could traverse GC heap and dump every object in the heap like this:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0:000&amp;gt;!dumpheap &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Address&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Size &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a71000 0015cde8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 Free &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a7100c 0015cde8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 Free &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a71018 0015cde8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 Free &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a71024 5ba58328&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 68 &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a71068 5ba58380&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 68 &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a710ac 5ba58430&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 68 &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a710f0 5ba5dba4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 68 &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ... &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a91000 5ba88bd8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2064 &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a91810 0019fe48&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2032 Free &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a92000 5ba88bd8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4096 &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a93000 0019fe48&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8192 Free &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00a95000 5ba88bd8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4096&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ... &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; total 1892 objects &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp; &amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Statistics: &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp; Count TotalSize Class Name &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5ba7607c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Security.Permissions.HostProtectionResource &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5ba75d54&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Security.Permissions.SecurityPermissionFlag &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5ba61f18&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Collections.CaseInsensitiveComparer &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ... &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0015cde8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 10260&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Free &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5ba57bf8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 318&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 18136 System.String &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;In this example, “DumpHeap” shows that there are 3 small free slots (They appear as special “Free” objects) at the beginning of the heap, followed by some objects with size 68 bytes. More interestingly, the statistics shows that there are 10,260 bytes Free objects (free space among live objects), and 18,136 bytes of string totally in the heap. If you find the Free objects take a very big percentage of the heap, the heap is fragmented (in whidbey, "DumpHeap" would do more analysis about heap fragmentation). In this case, you want to check the objects nearby the free space to see what they are and who holds their roots, you could do it using “DumpObj” and “GCRoot”:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0:000&amp;gt;!dumpobj 00a92000&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Name: System.Byte[]&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MethodTable 0x00992c3c&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EEClass 0x00992bc4&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Size 4096(0x1000) bytes&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Array: Rank 1, Type System.Byte&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Element Type: System.Byte&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0:000&amp;gt;!gcroot 00a92000&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Scan Thread 0 (728)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Scan Thread 1 (730)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ESP:88cf548:Root:05066b48(System.IO.MemoryStream)-&amp;gt;00a92000 (System.Byte[])&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ESP:88cf568:Root:05066b48(System.IO.MemoryStream)-&amp;gt;00a92000 (System.Byte[])&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Scan HandleTable 9b130&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Scan HandleTable 9ff18&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HANDLE(Pinned):d41250:Root: 00a92000 (System.Byte[]) &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;This shows that the object at address 00a92000 is a byte array, it's rooted by local variables in thread 1(to be precise, !GCRoot's output of roots in stack can't be trusted) and a pinned handle.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;And the command "ObjSize" list all handles including pinned ones:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0:000&amp;gt;!objsize&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HANDLE(Pinned):d41250: sizeof(00a92000) = 4096 ( 0x1000) bytes (System.Byte[])&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HANDLE(Pinned):d41254: sizeof(00a95000) = 4096 ( 0x1000) bytes (System.Byte[])&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HANDLE(Pinned):d41258: sizeof(00ac8b5b0) = 16 ( 0x10) bytes (System.Byte[])&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Using those Sos commands, you could get a clear picture if the heap is fragmented and how. I believe &lt;a href="https://blogs.msdn.com:443/mvstanton"&gt;Michael&lt;/A&gt;&amp;nbsp;will have more blogs about details of Sos.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;Solution&lt;o:p&gt;&lt;/o:p&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;In Everett a lot of work is done in GC to recognize fragmentation caused by pinning and alleviate the situation, more work is already done in Whidbey. So hopefully, the problem won't show up in Whidbey. But besides change in the platform, user code could do something to avoid the issue too. From above analysis, we could tell:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;If the pinned objects are allocated around same time, the free slots between each two objects would be smaller, and the situation is better.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;If pinning happens on older objects, it could cause fewer problems. Because older objects live at bottom of heap but most of free space is generated on top of heap.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;The shorter the objects are pinned, the easier GC could compact the heap&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;So if pinning becomes an issue which causes OOM for a .NET application, instead of creating new object to pin every time, developers could consider preallocating the to-be-pinned objects and reusing them. That way those objects would live close to each other in older part of GC heap and the heap won’t be fragmented that much. For example, if an application keeps pinning 1K buffers (consider the socket server case), we could use such a buffer pool to get the buffers:&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;public class BufferPool&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private const int INITIAL_POOL_SIZE = 512; // initial size of the pool&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private const int BUFFER_SIZE = 1024; // size of the buffers&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // pool of buffers&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private Queue m_FreeBuffers;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // singleton instance&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static BufferPool m_Instance = new BufferPool ();&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Singleton attribute&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static BufferPool Instance &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp;&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return m_Instance;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected BufferPool()&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; m_FreeBuffers = new Queue (INITIAL_POOL_SIZE);&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (int i = 0; i &amp;lt; INITIAL_POOL_SIZE; i++)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; m_FreeBuffers.Enqueue (new byte[BUFFER_SIZE]);&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // check out a buffer&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public byte[] Checkout (uint size) &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (m_FreeBuffers.Count &amp;gt; 0)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock (m_FreeBuffers)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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; if (m_FreeBuffers.Count &amp;gt; 0)&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&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;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (byte[])m_FreeBuffers.Dequeue ();&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // instead of creating new buffer, &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // blocking waiting or refusing request may be better&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new byte [BUFFER_SIZE];&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // check in a buffer&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Checkin (byte[] buffer)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock (m_FreeBuffers)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; m_FreeBuffers.Enqueue (buffer);&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;FONT face="Times New Roman" size=3&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;FONT face="Times New Roman" size=3&gt;This posting is provided "AS IS" with no warranties, and confers no rights. Use of included samples are subject to the terms specified at &lt;/FONT&gt;&lt;A href="http://www.microsoft.com/info/cpyright.htm" target=_blank&gt;&lt;FONT face="Times New Roman" size=3&gt;http://www.microsoft.com/info/cpyright.htm&lt;/FONT&gt;&lt;/A&gt;&lt;/FONT&gt;&lt;FONT face="Times New Roman"&gt;&lt;FONT size=3&gt;" &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoPlainText&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=63642" width="1" height="1"&gt;</content><author><name>yunjin</name><uri>http://blogs.msdn.com/members/yunjin.aspx</uri></author><category term=".NET programming gotcha and debugging tips" scheme="http://blogs.msdn.com/yunjin/archive/tags/.NET+programming+gotcha+and+debugging+tips/default.aspx" /><category term="CLR internal and Misc" scheme="http://blogs.msdn.com/yunjin/archive/tags/CLR+internal+and+Misc/default.aspx" /></entry></feed>