<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx</link><description>I've been doing a lot of thinking lately about foreach, and in what situations it may or may not create garbage. There have been some posts on the forums asking about it, and I recently found out that for some types, the enumerator that is created is</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1898088</link><pubDate>Sat, 17 Mar 2007 07:30:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1898088</guid><dc:creator>Ultrahead</dc:creator><description>&lt;p&gt;Nice read.&lt;/p&gt;
&lt;p&gt;One question: which would be the results if you use, say, a &amp;quot;List&amp;lt;IGameEntity&amp;gt; entities&amp;quot; collection? With something like: &lt;/p&gt;
&lt;p&gt;foreach (IGameEntity e in entities)&lt;/p&gt;
&lt;p&gt;{ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; e.Update(); &amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
</description></item><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1898310</link><pubDate>Sat, 17 Mar 2007 08:23:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1898310</guid><dc:creator>snprbob86</dc:creator><description>&lt;p&gt;Very interesting! Don't forget to investigate the &amp;quot;yield&amp;quot; key word :-)&lt;/p&gt;
</description></item><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1898313</link><pubDate>Sat, 17 Mar 2007 08:24:37 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1898313</guid><dc:creator>snprbob86</dc:creator><description>&lt;p&gt;Oh, and I forgot to mention: You are missing sign-in/log-out links on your blog. Since you have annonymous comments dissabled, I had to go to another MSDN blog to log in, then come back in order to post a comment.&lt;/p&gt;
</description></item><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1898545</link><pubDate>Sat, 17 Mar 2007 08:56:02 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1898545</guid><dc:creator>zygote</dc:creator><description>&lt;p&gt;Nice article. It seems foreach() isnt as bad as people have been making it sound :)&lt;/p&gt;
</description></item><item><title>XNA Weekly Roundup 12-03-07 to 18-03-07</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1903654</link><pubDate>Sun, 18 Mar 2007 04:45:33 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1903654</guid><dc:creator>Mykres Space</dc:creator><description>&lt;p&gt;Here we go with another Weekly Roundup from the XNA World. 05-03-2007 Code Release George has posted&lt;/p&gt;
</description></item><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1905008</link><pubDate>Sun, 18 Mar 2007 11:00:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1905008</guid><dc:creator>MichaelGiagnocavo</dc:creator><description>&lt;p&gt;It's been years since I look at anything on the CLR level, but every object in the CLR requires 12 bytes for the object header (syncblock and other stuff?). This is in addition to any actual data the object has.&lt;/p&gt;
</description></item><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1913364</link><pubDate>Mon, 19 Mar 2007 18:03:13 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1913364</guid><dc:creator>ShawnHargreaves</dc:creator><description>&lt;p&gt;Yeah. The one byte array will need some extra data for CLR infrastructure. This is true for any reference type or boxed value type, but not for value types that are living on the stack.&lt;/p&gt;
&lt;p&gt;I don't know precisely what that header contains, but if I had to guess I'd say maybe a four byte vtable pointer (which identifies the type of the object, and contains the indirection pointers for any virtual methods it may contain), plus a 4 byte array size counter, plus maybe 4 bytes for the garbage collector to tag which objects it has marked, implement write barriers and so on? (I'd guess the GC would pack quite a lot of data into an integer bitfield).&lt;/p&gt;
</description></item><item><title>A story about premature optimization</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1914663</link><pubDate>Tue, 20 Mar 2007 00:09:49 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1914663</guid><dc:creator>Shawn Hargreaves Blog</dc:creator><description>&lt;p&gt;Performance never ceases to be a fascinating topic. This forum thread inspired Eli to write about foreach&lt;/p&gt;
</description></item><item><title>XNA Weekly Roundup 18-03-07 to 26-03-07</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#1949307</link><pubDate>Mon, 26 Mar 2007 04:31:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1949307</guid><dc:creator>Mykres Space</dc:creator><description>&lt;p&gt;Ok here we go with this weeks update… It has been a relatively quite week in the world of XNA; this must&lt;/p&gt;
</description></item><item><title>Foreach and Garbage, Part 2</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#2184089</link><pubDate>Thu, 19 Apr 2007 04:41:14 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2184089</guid><dc:creator>Cornflower Blue</dc:creator><description>&lt;p&gt;As promised, here's a bit more about foreach and garbage. Last time I wrote about the Windows Desktop&lt;/p&gt;
</description></item><item><title>Twin paths to garbage collector nirvana</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#3666133</link><pubDate>Tue, 03 Jul 2007 05:14:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3666133</guid><dc:creator>Shawn Hargreaves Blog</dc:creator><description>&lt;p&gt;In my previous post I described how to tell if your Xbox garbage collection is taking too long. We saw&lt;/p&gt;
</description></item><item><title>re: [原创]如何改善Managed Code的Performance和Scalability系列之一：由for V.S. for each想到的</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#4280477</link><pubDate>Tue, 07 Aug 2007 20:22:21 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4280477</guid><dc:creator>cnblogs.com</dc:creator><description>&lt;p&gt;事实上对Array进行foreach的时候根本不会调用GetEnumerator()方法, 也就是被编译器给内联了. 而对于List&amp;amp;lt;&amp;amp;gt;, 虽然没有编译器内联GetEnumerator()&lt;/p&gt;
</description></item><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#9393852</link><pubDate>Wed, 04 Feb 2009 00:43:14 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9393852</guid><dc:creator>ShadowChaser</dc:creator><description>&lt;p&gt;This blog post inspired me to dig around a bit more into the internals of List&amp;lt;T&amp;gt; and Collection&amp;lt;T&amp;gt;.&lt;/p&gt;
&lt;p&gt;What's interesting is that all of the .NET enumerator types are structs - none are classes. What's really happening here is boxing, not allocation.&lt;/p&gt;
&lt;p&gt;Internally, instantating a new Collection&amp;lt;T&amp;gt; &amp;quot;wraps&amp;quot; a List&amp;lt;T&amp;gt; internally. The instance is placed into a variable typed as IList&amp;lt;T&amp;gt;.&lt;/p&gt;
&lt;p&gt;When Collection&amp;lt;T&amp;gt;.GetEnumerator() is called, a &amp;quot;List&amp;lt;T&amp;gt;.Enumerator&amp;quot; struct is returned. However, because GetEnumerator() returns IEnumerator&amp;lt;T&amp;gt;, the struct is boxed - resulting in the allocation.&lt;/p&gt;
&lt;p&gt;Apparently the C# foreach keyword has a bit of &amp;quot;magic&amp;quot; behavior - it doesn't entirely depend on IEnumerable. If a type has a public &amp;quot;subtype&amp;quot; named &amp;quot;Enumerator&amp;quot;, it instances that instead - no boxing!&lt;/p&gt;
&lt;p&gt;Because Collection&amp;lt;T&amp;gt; wraps IList&amp;lt;T&amp;gt;, it can't provide it's own public Enumerator subtype. Foreach is forced to use the IEnumerable interface, which boxes the struct into IEnumerator&amp;lt;T&amp;gt;.&lt;/p&gt;
&lt;p&gt;It also explains why casting List&amp;lt;T&amp;gt; to IList&amp;lt;T&amp;gt; causes the same behavior - the public Enumerator subtype is no longer 'visible' to foreach.&lt;/p&gt;
&lt;p&gt;I ran into a problem because I wanted to expose Collections of objects as properties in my classes instead of List - mainly due to class design guidelines and the fact I wanted to &amp;quot;hook&amp;quot; into SetItem/ClearItems/RemoveItem/InsertItem. This was for my &amp;quot;ScreenManager.Screens&amp;quot; property.&lt;/p&gt;
&lt;p&gt;On ScreenManager.Draw I was iterating over the collection, causing an allocation for each frame. I didn't want to rip out the Collection, either.&lt;/p&gt;
&lt;p&gt;There's a nice solution. Add a normal list to the class: &amp;quot;List&amp;lt;Screen&amp;gt; screenList&amp;quot; and wrap it with the collection: &amp;quot;Collection&amp;lt;Screen&amp;gt; screenCollection = new Collection&amp;lt;Screen&amp;gt;(screenList)&amp;quot;.&lt;/p&gt;
&lt;p&gt;Iterate over the screenList in the Draw method - no allocation will be performed since it can directly access the private List&amp;lt;Screen&amp;gt; and it's Enumerator sub-struct.&lt;/p&gt;
&lt;p&gt;The collection is directly exposed as the property, providing a clean interface for externally managing the screens.&lt;/p&gt;
&lt;p&gt;The only gotcha here is that modifications to the underlying List&amp;lt;Screen&amp;gt; type won't call the Collection's InsertItem/SetItem/ClearItems/RemoveItem protected virtual methods.&lt;/p&gt;
&lt;p&gt;The final pattern looks something like this:&lt;/p&gt;
&lt;p&gt;* Create a List&amp;lt;T&amp;gt; type in a class, make it private&lt;/p&gt;
&lt;p&gt;* Do not expose the List&amp;lt;T&amp;gt; type (keep it private)&lt;/p&gt;
&lt;p&gt;* Create a Collection&amp;lt;T&amp;gt; type, and pass the List&amp;lt;T&amp;gt; instance to it's constructor&lt;/p&gt;
&lt;p&gt;* Iterate using foreach (myListVariable) within the class to avoid boxing the iterator&lt;/p&gt;
&lt;p&gt;* Do not use List&amp;lt;T&amp;gt; for modifying the list - use Collection&amp;lt;T&amp;gt; instead&lt;/p&gt;
&lt;p&gt;* Expose Collection&amp;lt;T&amp;gt; as a public/protected property (as needed) to provide a clean interface to the collection. (see &lt;a rel="nofollow" target="_new" href="http://blogs.msdn.com/fxcop/archive/2006/04/27/585476.aspx"&gt;http://blogs.msdn.com/fxcop/archive/2006/04/27/585476.aspx&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Overkill for most situations, but useful in the &amp;quot;tight loop&amp;quot; game render-type code - even on the Windows platform.&lt;/p&gt;
</description></item><item><title>re: Foreach, Garbage, and the CLR Profiler</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#9420031</link><pubDate>Sat, 14 Feb 2009 00:22:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9420031</guid><dc:creator>Tiaan</dc:creator><description>&lt;p&gt;@ShadowChaser: How sure are you about that &amp;quot;magic&amp;quot; behavior of the C# foreach keyword and the instantiation logic you describe for a &amp;quot;subtype&amp;quot; named &amp;quot;Enumerator&amp;quot;? I would think that the compiler can figure this out by just looking at the implementation of the GetEnumerator method of the enumerable object over which the foreach keyword needs to iterate. &amp;nbsp;For example, the return type of Collection&amp;lt;T&amp;gt;.GetEnumerator is the generic IEnumerator&amp;lt;T&amp;gt; interface, which is also the case for IList&amp;lt;T&amp;gt;.GetEnumerator, while the &amp;quot;magic&amp;quot; List&amp;lt;T&amp;gt;.GetEnumerator returns List&amp;lt;T&amp;gt;.Enumerator (but this nested struct in turn also implements the generic IEnumerator&amp;lt;T&amp;gt; interface, such that List&amp;lt;T&amp;gt;.GetEnumerator is still a valid implementation of the IEnumerable&amp;lt;T&amp;gt;.GetEnumerator method). I find it hard to believe that the C# compiler would insist on you having to define a nested type called &amp;quot;Enumerator&amp;quot; for this optimization to work, but rather just insist on a specific value-type implementation of the IEnumerable&amp;lt;T&amp;gt; interface instead of just returning the basic interface itself from the enumerable's GetEnumerator method.&lt;/p&gt;
</description></item><item><title>0.033秒的艺术 --- for vs. foreach</title><link>http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx#9624382</link><pubDate>Sun, 17 May 2009 18:17:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9624382</guid><dc:creator>clayman</dc:creator><description>&lt;p&gt;关于C#中for和foreach孰优孰劣的争论似乎从来就没有停止过，各种谣言和真相混杂在一起，似乎变成了一个很复杂的问题.....&lt;/p&gt;
</description></item></channel></rss>