Steven Pratschner's .Net CF WebLoghttp://blogs.msdn.com/b/stevenpr/en-USTelligent Evolution Platform Developer Build (Build: 5.6.50428.7875)Another book update for “Customizing the Common Language Runtime”http://blogs.msdn.com/b/stevenpr/archive/2011/03/01/another-book-update-for-customizing-the-common-language-runtime.aspxTue, 01 Mar 2011 22:42:47 GMT91d46819-8472-40ad-a661-2c78acb4018c:10135714stevenpr0http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=10135714http://blogs.msdn.com/b/stevenpr/archive/2011/03/01/another-book-update-for-customizing-the-common-language-runtime.aspx#comments<p>&#160;</p> <p>&#160;</p> <p><font color="#000080" size="3">A reader recently pointed out another error in my hosting book.&#160; The error involves an API I used in the book that was cut before the final release went out.</font></p> <p><font color="#000080" size="3">On pages 253-256 I describe a hosting API named <font face="Courier New">IHostControl::GetDomainNeutralAssemblies</font>.&#160; The idea at the time was that this API could be used by a host to tell the CLR exactly which assemblies to load domain neutral.&#160; Unfortunately I published the book 6 months or so before the final product release (this was .Net Framework 2.0) and by the time the product shipped the CLR team had decided to remove the API.</font></p> <p><font color="#000080" size="3">As such, the options you have to tell the CLR which assemblies to load domain neutral aren’t nearly as granular.&#160; These options are represented by the enumeration called <font face="Courier New">LoaderOptimization</font>.&#160; This enumeration is described on page 252 of the book.</font></p> <p><font color="#000080" size="3">My apologies for this error.&#160; Bitten again by releasing the book before the product shipped…</font></p> <p><font color="#000080" size="3">Thanks,</font></p> <p><font color="#000080" size="3">Steven</font></p><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=10135714" width="1" height="1">The .Net Compact Framework Configuration Toolhttp://blogs.msdn.com/b/stevenpr/archive/2008/05/13/the-net-compact-framework-configuration-tool.aspxWed, 14 May 2008 00:24:51 GMT91d46819-8472-40ad-a661-2c78acb4018c:8501794stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=8501794http://blogs.msdn.com/b/stevenpr/archive/2008/05/13/the-net-compact-framework-configuration-tool.aspx#comments<p><font size="2">The .Net Compact Framework 3.5 </font><a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;displaylang=en"><font size="2">Power Toys</font></a><font size="2"> include a new utility called the NetCF Configuration Tool.</font></p> <p><font size="2">The Configuration Tool is a diagnostic tool.&#160; You won't typically use it in the course of everyday development, but it will come in handy for tasks like diagnosing failures related to device configuration and authoring configuration files.</font></p> <p><font size="2">While the tool isn't targeted at your application's end users, they will be able to use it with your help should you need them to provide you with information needed to debug a problem remotely.&#160; For this reason, the Configuration Tool runs directly on the mobile device instead of on a desktop machine connected to a device.</font></p> <p><font size="2">After describing how to install the tool, I'll discuss its four main functional areas:</font></p> <ul> <li><font size="2">Displaying which versions of NetCF are installed</font> </li> <li><font size="2">Displaying the contents of the Global Assembly Cache</font> </li> <li><font size="2">Authoring device.config files</font> </li> <li><font size="2">Authoring application configuration files</font> </li> </ul> <p>&#160;</p> <h2>Installing the Configuration Tool</h2> <p><font size="2">The Configuration Tool isn't automatically installed on the device when you install the Power Toys.&#160; Instead, you must copy it to your device manually. </font></p> <p><font size="2">Fortunately there's only one file to copy: <font face="Courier New" color="#004080">NetCFcfg.exe</font>. This file is OS and processor-specific so you'll find it under the appropriate WindowsCE directory in the .Net Compact Framework SDK.&#160; I'm running a WindowsMobile 5.0 device, so the Configuration Tool executable for my device is in: <font face="Courier New" color="#004080">C:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\wce500\armv4i</font></font> <font size="2">on my desktop machine.</font></p> <p><font size="2">It doesn't matter which directory you put the file in on your device.&#160; I usually put it in the <font face="Courier New" color="#004080">\windows</font> directory but you can deploy the file to any location you please.</font></p> <h2>The About tab</h2> <p><font size="2">The &quot;About tab&quot; describes which versions of NetCF are installed on a device.&#160; This is the tab that is displayed when you first launch the Configuration Tool:</font></p> <p><img src="http://farm3.static.flickr.com/2393/2478556401_7b9399ba4e_o.jpg" /> </p> <p><font size="2">It's not unusual to have more than one version of NetCF installed on a device. Most all Windows Mobile and WindowsCE devices come with a version of NetCF in ROM.&#160; Another version is often installed in RAM to support an application that requires a newer version of NetCF than the version that came with the device.</font></p> <p><font size="2">When multiple versions of NetCF are installed, it's not always obvious which version is being used to run your application.&#160; I've seen several cases where confusion results because an application is running with a different version than expected (see &quot;<a href="http://blogs.msdn.com/stevenpr/archive/2008/03/11/promoting-all-net-compact-framework-applications-on-a-device-using-device-config.aspx">promoting an application</a>&quot; for a general description of the rules used to determine which version of NetCF will be used to run an application).&#160; For example, remote tools like the <a href="http://blogs.msdn.com/stevenpr/archive/2008/05/08/the-clr-profiler-for-the-net-compact-framework-series-index.aspx">CLRProfiler</a> and <a href="http://blogs.msdn.com/stevenpr/archive/2007/10/26/what-s-new-in-the-remote-performance-monitor-for-net-compact-framework-3-5.aspx">Remote Performance Monitor</a> launch an application on device in order to profile it or gather other performance statistics.&#160; If your application is launched with a version of NetCF other than the one the tool is expecting, the application may start but the tool won't be able to gather the diagnostic information it is looking for.</font></p> <p><font size="2">Knowing which versions of NetCF are installed on the device, which version was used to build your application, and the rules used to determine which version will be used to run your application can help you determine whether any unexpected behavior you are seeing results from the &quot;wrong version of NetCF&quot; problem.</font></p> <h2>The GAC tab</h2> <p><font size="2">The GAC tab lists the assemblies installed in the Global Assembly Cache:</font></p> <p><img src="http://farm3.static.flickr.com/2382/2479375148_e85ff23040_o.jpg" /> </p> <p><font size="2">It helps to know the contents of the GAC when diagnosing assembly load failures.&#160; It may be you think an assembly is in the GAC when it isn't, or NetCF may load an assembly from the GAC when you don't expect it to.&#160; If you encounter a failure to load an assembly, use <a href="http://blogs.msdn.com/stevenpr/archive/2005/02/28/381744.aspx">Loader Logging</a> to find out why, then check the contents of the GAC using the Configuration Tool if the failure looks related to the GAC.</font></p> <p>&#160;</p> <h2>The Device Policy tab</h2> <p><font size="2">In a previous post I described how to use <a href="http://blogs.msdn.com/stevenpr/archive/2008/03/11/promoting-all-net-compact-framework-applications-on-a-device-using-device-config.aspx">device.config</a> to cause all applications on a device to run with a given version of NetCF.&#160; The Configuration Tool enables you to edit device.config using a GUI rather than having to modify the XML by hand.</font></p> <p><img src="http://farm3.static.flickr.com/2349/2486504869_8609701692_o.jpg" /> </p> <p><font size="2">The Device Policy tab let's you choose a version of NetCF to run all &quot;unconfigured&quot; applications on the device.&#160; By &quot;unconfigured&quot; I mean all applications that do not have an application configuration file that contains a <font face="Courier New" color="#004080">supportedRuntime</font> element.&#160; </font></p> <p><font size="2">In addition to the installed versions of NetCF, you can also select the value &quot;Default&quot;.&#160; Doing so will remove all <font face="Courier New" color="#004080">supportedRuntime</font> elements from device.config causing the device to revert to its default behavior for selecting a runtime. </font></p> <p><font size="2">Keep in mind that not all values you select on this tab are &quot;valid&quot; for all applications.&#160; For example,&#160; if I chose 1.0.4292 in the example above, no applications built with later versions of NetCF would run (unless they had configurations files of their own that overrode the device-wide setting).</font></p> <h2>The Application Policy tab</h2> <p><font size="2">In addition to specifying device-wide policy using the Device Policy tab, you can also specify which version of NetCF should be used to run a specific application by using the Application Policy tab.</font></p> <p><img src="http://farm3.static.flickr.com/2351/2487321046_9a525db7fd_o.jpg" /> </p> <p><font size="2">The top combo box on the Application Policy tab is pre-populated with all NetCF applications that are installed on the device.&#160; After selecting an application, use the lower combo box to select a version of NetCF to run the application.&#160; Under the covers this dialog is adding (or removing) <font face="courier " color="#004080">supportedRuntime</font> elements from your application's configuration file.</font></p> <p><font size="2">Any value chosen using the Application Policy tab overrides values chosen using the Device Policy tab.</font></p> <p><font size="2"></font></p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=8501794" width="1" height="1">The CLR Profiler for the .Net Compact Framework Series Indexhttp://blogs.msdn.com/b/stevenpr/archive/2008/05/08/the-clr-profiler-for-the-net-compact-framework-series-index.aspxFri, 09 May 2008 00:04:17 GMT91d46819-8472-40ad-a661-2c78acb4018c:8474552stevenpr3http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=8474552http://blogs.msdn.com/b/stevenpr/archive/2008/05/08/the-clr-profiler-for-the-net-compact-framework-series-index.aspx#comments<p><font size="2">I've completed all that I had planned to write (at least for now) about how to use the CLRProfiler with NetCF.</font>&#160; <font size="2">Here's a brief explanation and a link to each post the series:</font></p> <ul> <li><a href="http://blogs.msdn.com/stevenpr/archive/2007/10/17/the-clrprofiler-for-the-net-compact-framework-part-1-getting-started.aspx"><font size="2">Part I, Getting Started.</font></a><font size="2"> Describes how to install the profiler, launch an application, and begin collecting profiling data.</font></li> <li><a href="http://blogs.msdn.com/stevenpr/archive/2007/10/18/the-clrprofiler-for-the-net-compact-framework-part-ii-histograms-and-show-who-allocated.aspx"><font size="2">Part II, Histograms and &quot;Show Who Allocated&quot;.</font></a><font size="2"> The profiler displays various histograms you can use to determine the types and number of objects your application is allocating.&#160; You can also determine what methods in your application cause which types to get allocated.</font></li> <li><a href="http://blogs.msdn.com/stevenpr/archive/2007/11/28/the-clrprofler-for-the-net-compact-framework-part-iii-the-timeline-view.aspx"><font size="2">Part III, The Timeline View.</font></a><font size="2"> The timeline view shows the state of the GC heap over the lifetime of your application.</font></li> <li><a href="http://blogs.msdn.com/stevenpr/archive/2008/02/12/the-clrprofiler-for-the-net-compact-framework-part-iv-the-call-tree-view.aspx"><font size="2">Part IV, The Call Tree View.</font></a><font size="2"> Detailed information about every method call and every object allocation is shown in the Call Tree View.</font></li> <li><a href="http://blogs.msdn.com/stevenpr/archive/2008/04/22/the-clrprofiler-for-the-net-compact-framework-part-v-controlling-the-profiler-programmatically.aspx"><font size="2">Part V, Controlling the Profiler Programmatically.</font></a><font size="2"> The CLRProfiler generates a large amount of data and significantly slows down your application.&#160; You can programmatically control when the profiler runs using an API that you call from your application.&#160; This API also allows you to insert comments into the profile data and to take a snapshot of the GC on demand.</font></li> </ul> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=8474552" width="1" height="1">The CLRProfiler for the .Net Compact Framework, Part V: Controlling the profiler programmaticallyhttp://blogs.msdn.com/b/stevenpr/archive/2008/04/22/the-clrprofiler-for-the-net-compact-framework-part-v-controlling-the-profiler-programmatically.aspxWed, 23 Apr 2008 03:58:46 GMT91d46819-8472-40ad-a661-2c78acb4018c:8417658stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=8417658http://blogs.msdn.com/b/stevenpr/archive/2008/04/22/the-clrprofiler-for-the-net-compact-framework-part-v-controlling-the-profiler-programmatically.aspx#comments<p><font size="2">If you've used the CLRProfiler for NetCF you've probably noticed that your application runs much slower when being profiled.&#160; You likely have also seen the huge amount of data the profiler generates, even for relatively simple applications.&#160; The time it takes the profiler to run coupled with the volume of data it creates can sometimes make the profiler impractical to use.&#160; For example, I've had customers tell me that it can take several minutes to start an application while profiling.&#160; If it takes you several more minutes just to navigate to the portion of the application you'd like to profile, it can quickly become extremely frustrating.</font></p> <p><font size="2">The CLRProfiler ships with an additional assembly you can reference and call from your application to control the profiler while your application is running.&#160; This assembly, called <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> contains APIs you can use to start and stop profiling, insert comments into the profiling log, dump the contents of the GC heap on demand, and so on.&#160; The ability to control when the profiler collects data enables you to profile only the sections of your application you want to, rather than having the profiler collect data all the time.&#160; In this way, your application will start faster and there will be less data to sift through later.</font></p> <p><font size="2">In this post I'll describe how to use the APIs provided by the <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font>.</font></p> <p><font size="2"></font></p> <h2>Using the NetCFCLRProfilerControl Assembly</h2> <p><font size="2">The following steps are required to use <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> from your application:</font></p> <ol> <li><font size="2">Reference <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> in your Visual Studio project.</font></li> <li><font size="2">Add code to your application to call the APIs.</font></li> <li><font size="2">Deploy <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> along with your application.</font></li> <li><font size="2">Start your application using the CLRProfiler.</font></li> </ol> <h3>Referencing NetCFCLRProfilerControl</h3> <p><font size="2"><font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> is installed on the desktop machine in same directory as the <font face="Courier New" color="#0000ff">NetCFCLRProfiler</font> executable.&#160; On my machine the files are in <font face="Courier New" color="#0000ff">C:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\bin.&#160; </font></font></p> <p><font size="2">You'll need to add a reference from your application to <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> to use its APIs.&#160; If you're using Visual Studio you can add this reference using the standard &quot;Add Reference...&quot; dialog.&#160;&#160;&#160; </font></p> <h3>Public APIs</h3> <p><font size="2"><font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> contains one public class called <font face="Courier New" color="#0000ff">CLRProfilerControl</font> which contains the following public static members:</font></p> <table cellspacing="0" cellpadding="2" width="606" border="2"><tbody> <tr> <td valign="top" width="229"><font color="#0000a0" size="2">Member</font></td> <td valign="top" width="370"><font color="#0000a0" size="2">Notes</font></td> </tr> <tr> <td valign="top" width="229"> <p><font face="Courier New" color="#0000ff" size="2">bool ProcessIsUnderProfiler { get; }</font></p> </td> <td valign="top" width="370"><font size="2">Returns true if your application was launched using the CLRProfiler.&#160; Note that this is independent of whether the profiler is actually logging allocations or calls at the time. <br /></font></td> </tr> <tr> <td valign="top" width="229"> <p><font face="Courier New" color="#0000ff" size="2">bool AllocationLoggingActive { set; get; }</font> </p> </td> <td valign="top" width="370"><font size="2">A boolean property that controls whether the profiler logs managed allocations.</font></td> </tr> <tr> <td valign="top" width="229"> <p><font face="Courier New" color="#0000ff" size="2">bool CallLoggingActive { set; get; }</font> </p> </td> <td valign="top" width="370"><font size="2">A boolean property that controls whether the profiler logs method calls.</font></td> </tr> <tr> <td valign="top" width="229"> <p><font face="Courier New" color="#0000ff" size="2">void LogWriteLine(string comment)</font></p> <p><font face="Courier New" color="#0000ff" size="2">void LogWriteLine(string format, params object[] args)</font></p> </td> <td valign="top" width="370"><font size="2">Enables you to insert comments into the profiling log.&#160; These comments show up in the various profiler views to help you narrow down exactly where in your application certain allocations or calls were made.&#160; See the example later in this post.</font></td> </tr> <tr> <td valign="top" width="229"> <p><font face="Courier New" color="#0000ff" size="2">void DumpHeap()</font></p> </td> <td valign="top" width="370"><font size="2">Causes the profiler to display a graphical view of the GC heap.&#160; Individual views will also show up on the profiler's summary form when the application exits.</font></td> </tr> </tbody></table> <p>&#160;</p> <h3>Deploying your application</h3> <p><font size="2"><font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> is not installed on the device automatically.&#160; You'll need to deploy it along with your application.&#160; It's probably easiest to deploy <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> to the same directory as your application but you can also install it in the GAC if you prefer.</font></p> <h3>Launching your application</h3> <p><font size="2">The APIs provided by <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> have no effect if your application isn't started using the CLRProfiler.&#160; However, assuming you are going to use the APIs to control when the profiler logs allocations and/or calls, be sure to clear the relevant checkboxes on the profiler's main form before launching your application (otherwise you'll be logging all the stuff you wanted to prevent in the first place!).</font></p> <p><img src="http://farm4.static.flickr.com/3044/2434621505_5a6a359be3_o.jpg" /> </p> <p>&#160;</p> <p><font size="2">After clearing the checkboxes, start your application using the profiler as you always have.&#160; The actions of the profiler will now be controlled by your application instead of the CLRProfiler's user interface.</font></p> <p><font size="2"></font></p> <h2>Turning profiling on and off</h2> <p><font size="2">Assuming you've started your application with the &quot;Profile&quot; checkboxes on the profiler's main form cleared, no logging of allocations or calls will occur.&#160; You can turn profiling on using the <font face="Courier New" color="#0000ff">AllocationLoggingActive</font> and <font face="Courier New" color="#0000ff">CallLoggingActive</font> properties.</font></p> <p><font size="2">The following example turns allocation logging on just before entering a loop, then turns logging back off when the loop completes:</font></p> <p><font face="Courier New" color="#0000ff" size="2">private void btnCheckOut_Click(object sender, EventArgs e) <br />{ <br />&#160;&#160;&#160; <strong>CLRProfilerControl.AllocationLoggingActive = true;</strong> <br />&#160;&#160;&#160; for (int i = 0; i &lt; 20; i++) <br />&#160;&#160;&#160; { <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; m_cart.ProcessCart(); <br />&#160;&#160;&#160; } <br />&#160;&#160;&#160; <strong>CLRProfilerControl.AllocationLoggingActive = false; <br /></strong>}</font></p> <h2>Inserting comments into the profiling log</h2> <p><font size="2">The ability to insert comments into the profiling log is a cool feature that enables you to place your own visual markers into some of the profiler's graphical views.&#160; </font></p> <p><font size="2">Here's an example that inserts comments denoting the beginning and end of the execution of a loop:</font></p> <p><font face="Courier New" color="#0000ff" size="2">private void btnCheckOut_Click(object sender, EventArgs e) <br />{ <br />&#160;&#160;&#160; <strong>CLRProfilerControl.LogWriteLine(&quot;Before ProcessCart loop&quot;);</strong> <br />&#160;&#160;&#160; for (int i = 0; i &lt; 20; i++) <br />&#160;&#160;&#160; { <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; m_cart.ProcessCart(); <br />&#160;&#160;&#160; } <br />&#160;&#160;&#160; <strong>CLRProfilerControl.LogWriteLine(&quot;After ProcessCart loop&quot;);</strong> <br />}</font></p> <p><font size="2">After the application exits, your comments show up in several places in the CLRProfiler UI.&#160; First, the summary screen includes a button that brings up a window giving the timestamp of each comment.&#160; You can use this as a rudimentary timing mechanism in your application:</font></p> <p><font size="2"><img src="http://farm4.static.flickr.com/3067/2435477454_cd9a29e505_o.jpg" /> </font></p> <p><font size="2">The comments also show up in various views throughout the UI&#160; For example, in the Timeline View, the comments show up as vertical green lines that indicate the time at which the comment was logged.&#160; You can see the text of a given comment by hovering the house over its green line.&#160; This allows you to see the state of the GC heap between different points of interest as your application ran.</font></p> <p><font size="2"><img src="http://farm3.static.flickr.com/2348/2434661163_2513122be5.jpg" /> </font></p> <p><font size="2"></font></p> <h2>Dumping the GC Heap</h2> <p><font size="2">The final feature available via <font face="Courier New" color="#0000ff">NetCFCLRProfilerControl</font> is the ability to take a snapshot of the GC heap on demand.&#160; The <font face="Courier New" color="#0000ff">DumpHeap</font> method causes a heap view to be displayed immediately.&#160; You can also access all the heap views taken while the app ran from the Summary View after the application exits.</font></p> <p>&#160;</p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=8417658" width="1" height="1">Promoting all .Net Compact Framework Applications on a device using device.confighttp://blogs.msdn.com/b/stevenpr/archive/2008/03/11/promoting-all-net-compact-framework-applications-on-a-device-using-device-config.aspxWed, 12 Mar 2008 03:01:01 GMT91d46819-8472-40ad-a661-2c78acb4018c:8163618stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=8163618http://blogs.msdn.com/b/stevenpr/archive/2008/03/11/promoting-all-net-compact-framework-applications-on-a-device-using-device-config.aspx#comments<p><font size="2">By default, a managed device application is run with the version of the .Net Compact Framework it was built with.&#160; Only if that version is not present on the device will we &quot;promote&quot; the application to run with the latest installed version.&#160; This policy is considered safe and conservative because it isolates applications from unintended compatibility changes that may be introduced in new version of the Framework, at least in the most common scenario.</font></p> <p><font size="2">However, there are times when you may want to run an application with a version of NetCF other than the one it was built with.&#160; For example you may find that a newer version of NetCF performs better and is more stable than a previous version so you'd like to take advantage of those improvements without having to rebuild your application.&#160; Several previous blog posts (see <a title="http://blogs.msdn.com/davidklinems/archive/2005/11/09/491113.aspx" href="http://blogs.msdn.com/davidklinems/archive/2005/11/09/491113.aspx">http://blogs.msdn.com/davidklinems/archive/2005/11/09/491113.aspx</a>) have shown how to do this using an application configuration file.&#160; This approach is manageable as long as you only have a few applications to promote.&#160; But if you'd like to promote a large number of applications it can quickly become a hassle to author all these configuration files and manage their deployment and updates.</font></p> <p><font size="2">Fortunately, version 3.5 of the Compact Framework lets you promote all applications on a device using a single device-wide configuration file.&#160; The syntax of this configuration file is the same as that used in the application configuration file: you specify the version of NetCF you'd like to run all applications with using the <font face="Courier New" color="#004080">supportedRuntime</font> element.&#160; The device-wide configuration file must be called <font face="Courier New" color="#004080">device.config</font> and must be located in the <font face="Courier New" color="#004080">\windows</font> directory.</font></p> <p><font size="2"></font></p> <p><font size="2">Here's the contents of a sample <font face="Courier New" color="#004080">device.config</font> that will cause all applications to be run with .Net Compact Framework version 3.5:</font></p> <p><font face="Courier New" color="#004080" size="2">&lt;configuration&gt; <br />&#160;&#160;&#160; &lt;startup&gt; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;supportedRuntime version=&quot;v3.5.7238&quot;/&gt; <br />&#160;&#160;&#160; &lt;/startup&gt; <br />&lt;/configuration&gt;</font></p> <p><font face="Courier New" color="#004080" size="2"></font></p> <p><font face="ver" color="#000000" size="2">There's one more case to consider.&#160; Suppose you've used <font face="Courier New" color="#004080">device.config</font> to promote all your applications only to discover that one of your applications doesn't work properly.&#160; In this scenario you'd want to &quot;roll back&quot; just that one application to the version it was built with.&#160; You'd do this by authoring an application configuration file for that application.&#160; Any <font face="Courier New" color="#004080">supportedRuntime</font> settings present in application configuration files will override the settings specified in <font face="Courier New" color="#004080">device.config</font> thus giving you a quick way to opt-out of your global policy.</font></p> <p><font color="#000000" size="2">Thanks,</font></p> <p><font color="#000000" size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=8163618" width="1" height="1">The CLRProfiler for the .Net Compact Framework, Part IV: The Call Tree Viewhttp://blogs.msdn.com/b/stevenpr/archive/2008/02/12/the-clrprofiler-for-the-net-compact-framework-part-iv-the-call-tree-view.aspxTue, 12 Feb 2008 21:10:23 GMT91d46819-8472-40ad-a661-2c78acb4018c:7649678stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=7649678http://blogs.msdn.com/b/stevenpr/archive/2008/02/12/the-clrprofiler-for-the-net-compact-framework-part-iv-the-call-tree-view.aspx#comments<p><font size="2">This series of posts provides an introduction to using the CLRProfiler for the .Net Compact Framework.&#160; In previous posts (<a href="http://blogs.msdn.com/stevenpr/archive/2007/10/17/the-clrprofiler-for-the-net-compact-framework-part-1-getting-started.aspx">part 1</a>, <a href="http://blogs.msdn.com/stevenpr/archive/2007/10/18/the-clrprofiler-for-the-net-compact-framework-part-ii-histograms-and-show-who-allocated.aspx">part 2</a>, and <a href="http://blogs.msdn.com/stevenpr/archive/2007/11/28/the-clrprofler-for-the-net-compact-framework-part-iii-the-timeline-view.aspx">part 3</a>) we've looked at various profiler features as we try to solve a performance problem with a sample application.&#160; So far, we've learned that our performance problem is due to excessive boxing of value types.&#160; We've also learned what type of objects we are boxing and what methods in the sample are causing the boxing to occur.</font></p> <p><font size="2">In some cases, knowing which method is causing the problem is all you need, especially if the method is small and straightforward.&#160; However, there are cases where even more detail is needed.&#160; In this post I'll use the Call Tree View to determine the <em>exact line of source code</em> that is causing my performance issue!</font></p> <p><font size="2">After you've finished profiling, you can bring up the Call Tree View from the summary page:</font></p> <p><font size="2"></font></p> <p><img src="http://farm3.static.flickr.com/2002/2231705450_aee3a468b8.jpg" /> </p> <p>&#160;</p> <h1>The Call Tree View</h1> <p><font size="2">The Call Tree View shows every allocation made as a result of every method call.&#160; For all but the simplest programs the Call Tree View contains a huge amount of data.&#160; Fortunately, navigating through all this data isn't very hard once you get used to a few tricks.</font></p> <p><font size="2">Method calls are shown in black and object allocations are shown in green.&#160; For example, the following picture shows the initial state of the Call Tree View.&#160; You can see that only one method (the program's <font face="Courier New">Main</font> method) has been called at this outermost level.&#160; You can also see that several allocations have already been made.&#160; These initial allocations are made by the CLR just before it starts executing a program.&#160; As you can see, these initial allocations represent several of the common exception types as well as the initial Application Domain.</font></p> <p><img src="http://farm3.static.flickr.com/2125/2230902073_7c65acbb7e.jpg" /> </p> <p><font size="2">Along with the individual method calls and object allocations, the Call Tree View also shows summary statistics such as the number of method calls that result from a given call, the number of bytes and objects allocated by a given call and so on.&#160; You can sort the data either by number of calls or by the amount of memory allocated.</font></p> <p><font size="2">As you start to expand the tree, you'll notice that one child node at each level is highlighted in bold.&#160; The highlighted node represents the method that has allocated the most memory (or generated the most calls, depending on your sort preference).&#160; This is the key to drilling into the data quickly - just follow the highlighted nodes until you find the method you are looking for.</font></p> <p>&#160;</p> <h2>Back to the Example</h2> <p><font size="2">In previous posts we've established that the objects we are boxing are of type <font face="Courier New">Box.Block</font> and that the boxing is occurring in calls to <font face="Courier New">RotateGameBlocks</font> and <font face="Courier New">InitializeGameBlocks</font>.&#160; By drilling through the data in the Call Tree View we can find out exactly which line of code in <font face="Courier New">RotateGameBlocks</font> (or <font face="Courier New">InitializeGameBlocks</font>) is causing the boxing to occur.</font></p> <p><font size="2">The following picture shows the result of following the highlighted notes until I have found the <font face="Courier New">RotateGameBlocks</font> method.&#160; Some of the methods in the tree look familiar, like <font face="Courier New">Main</font>, and <font face="Courier New">Application.Run</font>, but many methods don't.&#160; Method names that you don't recognize are likely part of NetCF's internal implementation.&#160; For example, methods that contain &quot;<font face="Courier New">AGL</font>&quot; in their name are part of NetCF's implementation of Windows Forms. </font></p> <p><font size="2"><img src="http://farm3.static.flickr.com/2147/2230902115_e5b90213f5.jpg" /> </font></p> <p><font size="2">When looking at the child nodes of <font face="Courier New">RotateGameBlocks</font>, we see a green line representing the allocations of <font face="Courier New">Box.Block</font>.&#160; The Objects column tells us that a call to <font face="Courier New">RotateGameBlocks</font> causes 14,400 instances of <font face="Courier New">Box.Block</font> to be allocated.&#160; Furthermore, we can see that <font face="Courier New">RotateGameBlocks</font> calls <font face="Courier New">ArrayList.set_Item</font> 14,400 times.&#160; The fact that the number of calls to <font face="Courier New">ArrayList.set_Item</font> and the number of instances of <font face="Courier New">Box.Block</font> that are allocated are the same indicates that the calling <font face="courier ">ArrayList.set_Item</font> is the line in my sample that is causing our boxing to occur.</font></p> <p><font size="2">In my next post I'll describe a set of managed APIs you can use to control profiling programmatically.</font></p> <p>&#160;</p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p><font size="1">This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</font></p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=7649678" width="1" height="1">DiagnosticsPowerToys for the .Net Compact Framework version 3.5 now released!http://blogs.msdn.com/b/stevenpr/archive/2007/12/10/powertoys-for-the-net-compact-framework-version-3-5-now-released.aspxTue, 11 Dec 2007 02:21:57 GMT91d46819-8472-40ad-a661-2c78acb4018c:6728543stevenpr6http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=6728543http://blogs.msdn.com/b/stevenpr/archive/2007/12/10/powertoys-for-the-net-compact-framework-version-3-5-now-released.aspx#comments<p><font size="2">We've just released the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;displaylang=en">final 3.5 version of the PowerToys for NetCF</a> to the web.&#160; </font></p> <p><font size="2">You'll need to install the 3.5 NetCF runtime on your device to use these tools.&#160; For now, you can get the correct runtime by installing <a href="http://msdn.microsoft.com/">Visual Studio 2008</a>.&#160; In a few weeks we hope to post a standalone install for NetCF 3.5.</font></p> <p><font size="2">The PowerToys release includes all the tools you need to diagnose issues in your .Net device applications, including the <a href="http://blogs.msdn.com/stevenpr/archive/2007/10/26/what-s-new-in-the-remote-performance-monitor-for-net-compact-framework-3-5.aspx">Remote Performance Monitor</a>, <a href="http://blogs.msdn.com/stevenpr/archive/2007/10/17/the-clrprofiler-for-the-net-compact-framework-part-1-getting-started.aspx">CLR Profiler</a>, the <a href="http://blogs.msdn.com/danhorbatt/archive/2007/11/01/remote-logging-wcf-on-net-compact-framework.aspx">Logging Utility</a> and more...</font></p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font>&#160;</p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=6728543" width="1" height="1">The CLRProfler for the .Net Compact Framework, Part III: The Timeline Viewhttp://blogs.msdn.com/b/stevenpr/archive/2007/11/28/the-clrprofler-for-the-net-compact-framework-part-iii-the-timeline-view.aspxWed, 28 Nov 2007 22:31:37 GMT91d46819-8472-40ad-a661-2c78acb4018c:6583673stevenpr5http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=6583673http://blogs.msdn.com/b/stevenpr/archive/2007/11/28/the-clrprofler-for-the-net-compact-framework-part-iii-the-timeline-view.aspx#comments<p><font size="2">In the first two parts of this series (<a href="http://blogs.msdn.com/stevenpr/archive/2007/10/17/the-clrprofiler-for-the-net-compact-framework-part-1-getting-started.aspx">part 1</a> and <a href="http://blogs.msdn.com/stevenpr/archive/2007/10/18/the-clrprofiler-for-the-net-compact-framework-part-ii-histograms-and-show-who-allocated.aspx">part 2</a>) I described how to get started using the CLRProfiler and how to use the histograms and the &quot;Show Who Allocated&quot; view to see what types of objects you're allocating and to determine where in your application the allocations are occurring.</font></p> <p><font size="2">In this post I'll talk about my favorite view: the Timeline view.&#xA0; I like the Timeline view because it lets you look at the contents of the GC heap over time.&#xA0; Using this view you can see not only where in your application you are allocating objects, but when. You can also see which objects are collected each time the GC ran.&#xA0; By including a time dimension, the Timeline view combined with &quot;Show Who Allocated&quot; can give you a complete picture of how the use of managed memory varies as your application runs.</font></p> <p><font size="2">After you've completed profiling, you can launch the Timeline view from the Summary page:</font></p> <p><img id="id" src="http://farm3.static.flickr.com/2260/2072014366_1a62e96f25.jpg" /> </p> <p>&#xA0;</p> <h1>The Timeline View</h1> <p><font size="2">The Timeline view has two panes.&#xA0; The right hand pane is the legend and the left hand pane is the contents of the heap.&#xA0; As with the histograms we looked at in part 2, the colors in the legend describe the types of objects present in the heap.&#xA0; Free space in the heap is always white:</font></p> <p><img id="id" src="http://farm3.static.flickr.com/2183/2072014404_edee84895b.jpg" /> </p> <p><font size="2">The horizontal axis in this view represents time.&#xA0; If you look at the axis you can see when each GC occurred as indicated by the vertical blue markers.&#xA0; By correlating each GC with the contents of the heap displayed above you can get a sense for which objects were freed in each collection.</font></p> <p><font size="2"><font color="#800000"><strong>Note:</strong> <em>You may notice that each GC is labeled with a generation.&#xA0; The Compact Framework's garbage collector doesn't have the notion of generations so these markers are an artifact of the code we ported from the full .Net Framework. You can ignore them.</em></font></font></p> <p><font size="2">The vertical axis in the timeline view shows object addresses in the heap.&#xA0; Given that the segments of the GC heap are not necessary contiguous you may seen gaps in these numbers.&#xA0; If you'd like more information about the Compact Framework GC check out the following posts:</font></p> <ul> <li><font size="2"><a href="http://blogs.msdn.com/stevenpr/archive/2004/07/26/197254.aspx">An Overview of the .Net Compact Framework's Garbage Collector</a></font></li> <li><font size="2"><a href="http://blogs.msdn.com/stevenpr/archive/2005/12/14/503818.aspx">GC Heap Management</a></font></li> <li><font size="2"><a href="http://community.opennetcf.com/articles/cf/archive/2007/08/10/don-t-fear-the-garbage-collector.aspx">Don't Fear the Garbage Collector</a></font></li> </ul> <h2>Back to the Example</h2> <p><font size="2">Throughout this series of posts I've been using an example of a game I wrote that paints way too slowly.&#xA0; In part 2 we saw that the vast majority of objects I'm creating are of type <font face="Courier New">Box.Block</font>.&#xA0; Looking that the Timeline view confirms this as can be seen by looking at the legend and all the red in the view of the heap.&#xA0; </font></p> <p><font size="2">The time-based nature of this view allows us to get a few steps deeper into our analysis.&#xA0; First, we can see the points in time at which allocations of our <font face="Courier New">Blocks</font> occurred.&#xA0; In this case, that data isn't very interesting because the view tells me that I was almost continually allocating <font face="Courier New">Blocks</font>. </font></p> <p><font size="2">What's more important in my case is to discover which method in my application was doing the allocations at which point in time.&#xA0; It may be that early on in my application my allocations were coming from <font face="Courier New">MethodA</font> while later on they were coming from <font face="Courier New">MethodB</font>.&#xA0; This time-based analysis can be particularly useful if you'd like to see all that's happening when your application first starts, for example.</font></p> <p><font size="2">To see where your allocations are coming from at a given point in time just select that time in the view.&#xA0; This causes a vertical line to appear at that point in the graph.&#xA0; Then right-click and select &quot;Show Who Allocated&quot; from the context menu:</font></p> <p><img id="id" src="http://farm3.static.flickr.com/2149/2072014384_e3976a9ce6_o.jpg" /> </p> <p><font size="2"></font></p> <p><font size="2">Doing so brings up the same Allocation Graph we looked at in part 2, except that the graph shows only the allocations done at that particular point in time.&#xA0; In part 2 we saw that my allocations were coming from two methods: <font face="Courier New">InitializeGameBlocks</font> and <font face="Courier New">RotateGameBlocks</font>.&#xA0; By using the timeline view I can see which of those methods was called at which times during my application.&#xA0; </font></p> <p><font size="2">Next time I'll describe the Call Tree view that will show even more detail by highlighting the exact lines within my methods that are causing the spurious allocations to occur.</font></p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights</p> <p> <p><font size="2"></font></p></p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=6583673" width="1" height="1">Calling the EnumServices Win32 API from your .Net Compact Framework Applicationhttp://blogs.msdn.com/b/stevenpr/archive/2007/11/20/calling-the-enumservices-win32-api-from-your-net-compact-framework-application.aspxWed, 21 Nov 2007 04:07:51 GMT91d46819-8472-40ad-a661-2c78acb4018c:6447873stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=6447873http://blogs.msdn.com/b/stevenpr/archive/2007/11/20/calling-the-enumservices-win32-api-from-your-net-compact-framework-application.aspx#comments<p><font size="2">I was helping a customer use PInvoke to call <font face="Courier New">EnumServices</font> today and got stuck a few times so I thought it may be helpful to post the solution in case anyone else runs into this someday.</font></p> <p><font size="2"><font face="Courier New">EnumServices</font> returns a buffer containing a number of structures of type <font face="Courier New">ServiceEnumInfo</font> that describe basic information about the services on a device.</font></p> <p><font size="2">Each <font face="Courier New">ServiceEnumInfo</font> structure contains an embedded character array that represents the service's prefix and a pointer to a string that represents the name of the dll that implements the service.&#xA0; The dll names corresponding to the structures are laid out in memory just after the structures themselves.&#xA0; So the contents of the buffer you get back from calling <font face="Courier ">EnumServices</font> looks like this (this example is from a device with 3 services):</font></p> <p><font size="2"><img id="id" src="http://farm3.static.flickr.com/2156/2051602442_f2d9d48900_o.jpg" /> </font></p> <p><font size="2"></font></p> <p><font size="2">Here's some sample code that calls <font face="Courier New">EnumServices</font> and loops the buffer pulling out both the prefix name and the dll name for each service:</font></p> <p><font color="#004080">using System; <br />using System.Collections.Generic; <br />using System.ComponentModel; <br />using System.Data; <br />using System.Drawing; <br />using System.Text; <br />using System.Windows.Forms; <br />using System.Runtime.InteropServices; <br />using System.Diagnostics; </font></p> <p><font color="#004080">namespace EnumServices <br />{ <br />&#xA0;&#xA0;&#xA0; public partial class Form1 : Form <br />&#xA0;&#xA0;&#xA0; { <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // Managed definition of the native ServiceEnumInfo structure.&#xA0; Here's the corresponding native definition: <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // typedef struct_ServiceEnumInfo { <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; //&#xA0;&#xA0;&#xA0; WCHAR szPrefix[6]; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; //&#xA0;&#xA0;&#xA0; WCHAR szDllName; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; //&#xA0;&#xA0;&#xA0; HANDLE hServiceHandle; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; //&#xA0;&#xA0;&#xA0; DWORD dwServiceState; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // } ServiceEnumInfo; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; struct ServiceEnumInfo <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; { <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=6)] public String prefixName; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; public IntPtr pDllName; // this value is a pointer to the dll name - not the dll name itself. <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; public IntPtr hServiceHandle; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; public int dwServiceState; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; } </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; [DllImport(&quot;coredll.dll&quot;)] <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; private static extern int EnumServices(IntPtr pBuffer, ref int numEntries, ref int cbBuf); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; public Form1() <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; { <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; InitializeComponent(); <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; } </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; private void btnServices_Click(object sender, EventArgs e) <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; { <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; int numEntries = 0; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; int cbSize = 0; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; int structSize = Marshal.SizeOf(typeof(ServiceEnumInfo)); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // call once to get required buffer size <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; int result = EnumServices(IntPtr.Zero, ref numEntries, ref cbSize); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // alloc a buffer of the correct size <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; IntPtr pBuffer = Marshal.AllocHGlobal(cbSize); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // call again to get the real stuff <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; result = EnumServices(pBuffer, ref numEntries, ref cbSize); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // loop through the structure pulling out the prefix and the dll name <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; for (int i = 0; i &lt; numEntries; i++) <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; { <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // move a pointer along to point to the &quot;current&quot; structure each time through the loop <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; IntPtr pStruct = new IntPtr(pBuffer.ToInt32()+ (i * structSize)); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // &quot;translate&quot; the pointer into an actual structure <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; ServiceEnumInfo sei = (ServiceEnumInfo)Marshal.PtrToStructure(pStruct, </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; typeof(ServiceEnumInfo)); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; string prefix = sei.prefixName; <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; string dllName = Marshal.PtrToStringUni(sei.pDllName); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // use the prefix and dllName as needed.... <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; Debug.WriteLine(prefix); <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; Debug.WriteLine(dllName); <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; } </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; // remember to free the buffer that we allocated <br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; Marshal.FreeHGlobal(pBuffer); </font></p> <p><font color="#004080">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; } <br />&#xA0;&#xA0;&#xA0; } <br />}</font></p> <p><font color="#004080" size="2"></font></p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=6447873" width="1" height="1">Great .Net Compact Framework Content at Oredevhttp://blogs.msdn.com/b/stevenpr/archive/2007/11/09/great-net-compact-framework-content-at-oredev.aspxSat, 10 Nov 2007 03:47:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:6034039stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=6034039http://blogs.msdn.com/b/stevenpr/archive/2007/11/09/great-net-compact-framework-content-at-oredev.aspx#comments<P><FONT size=2>Next week is the annual </FONT><FONT size=2><A href="http://www.oredev.org/" mce_href="http://www.oredev.org">Øredev</A> </FONT>conference in Malmö, Sweden.&nbsp; We're very fortunate to have 3 detailed .Net Compact Framework sessions there.&nbsp; Doug Boling will be doing sessions on <A href="http://www.oredev.org/toppmeny/conference/embeddedsystem/compactframeworkperformance.4.76e8b1c6112f078db498000127374.html" mce_href="http://www.oredev.org/toppmeny/conference/embeddedsystem/compactframeworkperformance.4.76e8b1c6112f078db498000127374.html">performance</A> and on how to <A href="http://www.oredev.org/toppmeny/conference/embeddedsystem/towritegpsenabledapplications.4.76e8b1c6112f078db498000127345.html" mce_href="http://www.oredev.org/toppmeny/conference/embeddedsystem/towritegpsenabledapplications.4.76e8b1c6112f078db498000127345.html">enable GPS in your applications</A> and I'll be doing a session on how to use the <A href="http://www.oredev.org/toppmeny/conference/embeddedsystem/newandimproveddiagnostictools.4.76e8b1c6112f078db498000129363.html" mce_href="http://www.oredev.org/toppmeny/conference/embeddedsystem/newandimproveddiagnostictools.4.76e8b1c6112f078db498000129363.html">.Net Compact Framework diagnostic tools</A> to solve tough issues like performance problems or memory leaks.&nbsp; </FONT></P>
<P>I'll also be presenting a session on <A href="http://www.oredev.org/toppmeny/conference/net/silverlightindepth.4.76e8b1c6112f078db498000126618.html" mce_href="http://www.oredev.org/toppmeny/conference/net/silverlightindepth.4.76e8b1c6112f078db498000126618.html">Silverlight 1.1</A>.</P>
<P>If you're in that part of the world next week it's a great chance to get access to some .Net Compact Framework content.&nbsp; Doug Boling knows a ton about WindowsCE and is a great resource.</P>
<P><FONT size=2>Thanks,</FONT></P>
<P><FONT size=2>Steven</FONT></P>
<P>This posting is provided "AS IS" with no warranties, and confers no rights.</P>
<P><FONT size=2></FONT></P><img src="http://blogs.msdn.com/aggbug.aspx?PostID=6034039" width="1" height="1">What's new in the Remote Performance Monitor for .Net Compact Framework 3.5http://blogs.msdn.com/b/stevenpr/archive/2007/10/26/what-s-new-in-the-remote-performance-monitor-for-net-compact-framework-3-5.aspxSat, 27 Oct 2007 03:40:18 GMT91d46819-8472-40ad-a661-2c78acb4018c:5697670stevenpr6http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=5697670http://blogs.msdn.com/b/stevenpr/archive/2007/10/26/what-s-new-in-the-remote-performance-monitor-for-net-compact-framework-3-5.aspx#comments<p><font size="2">The <a href="http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx">Remote Performance Monitor (RPM)</a> first shipped in version 2 service pack 1 of the .Net Compact Framework.&#xA0; Since that time, numerous customers have come to depend on RPM to help them diagnose performance problems and find memory leaks in their applications.&#xA0; With each release we add new features and fix bugs based on what customers tell us is important, and version 3.5 is no exception.&#xA0; This post summarizes what's new in v3.5.&#xA0; </font></p> <h1>Emulator support</h1> <p><font size="2">One of the most glaring omissions from RPM in previous releases was the lack of support for emulators.&#xA0; Thankfully, in version 3.5 you can use the WindowsMobile and WindowsCE emulators with RPM just as you would a &quot;real&quot; device.</font></p> <h1>Auto-deployment of device-side components</h1> <p><font size="2">The 3.5 version of RPM no longer requires any manual setup steps.&#xA0; Previously, you had to manually copy <font face="Courier New">netcfrtl.dll</font> and the VSD transports to your device before using RPM.&#xA0; Now, RPM does everything for you: if anything RPM depends on is missing from your device, those dependencies will be copied before you launch an application.</font></p> <h1>New User Interface</h1> <p><font size="2">RPM's user interface has been streamlined to make the process of collecting and browsing performance statistics and analyzing GC heap dumps easier.&#xA0; We've removed the use of MDI to manage windows, simplified the menu options and added a dialog used to launch applications.&#xA0; Here's a screenshot of a section of the new UI.&#xA0; None of us are UI gurus here on the .Net Compact Framework team, but we hope our new approach is an improvement.</font></p> <p><img id="id" src="http://farm3.static.flickr.com/2083/1765778587_379f64c9d6.jpg" /> </p> <p><font size="2">We also keep track of the applications you've previously launched so you don't have to retype them every time.&#xA0; I always hated that....</font></p> <p><font size="2"></font></p> <h1>Improved Device Management</h1> <p><font size="2">RPM now includes a new component that lets you manage the devices you'd like to connect to.&#xA0; The following device management form can be accessed from the Browse button on the launch dialog (see the previous picture):</font></p> <p><font size="2"><img id="id" src="http://farm3.static.flickr.com/2141/1765778441_5670955012.jpg" /> </font></p> <p><font size="2">This dialog makes it much easier for you to work with your devices.&#xA0; As with previous releases, RPM knows about Active Sync devices automatically.&#xA0; You can now add and save devices connected over tcp/ip so you don't have to retype the addresses each time you'd like to use the device.&#xA0; You can also set various device properties and designate one of your devices as the default device.&#xA0; Tagging a device as the default causes it to be automatically selected when the launch dialog is displayed.</font></p> <h1>Remote Installation of .Net CF</h1> <p><font size="2">Installing .Net CF into RAM typically involves either rerunning the SDK setup program or browsing through your file system searching for the correct cab to install, manually copying it to the device and launching the cab installer. With RPM 3.5 you can install Net CF onto your device using the device management dialog as shown below:</font></p> <p><img id="id" src="http://farm3.static.flickr.com/2134/1765829657_759ad6ee77_o.jpg" /> </p> <h1>&#xA0;</h1> <h1>&#xA0;</h1> <p><font size="2">RPM will detect the version of the OS on the device, along with the processor type, and deploy the correct cab file.</font></p> <p><font size="2"></font></p> <h1>Deployment of your application from RPM</h1> <p><font size="2">If the application you'd like to launch isn't present on your device, you can now use RPM to deploy it.&#xA0; On the launch dialog you'll see two fields: &quot;</font><font size="2"><em>Deploy application from</em>&quot; and &quot;<em>Application</em>&quot;:</font></p> <p><img id="id" src="http://farm3.static.flickr.com/2083/1765778587_379f64c9d6.jpg" /> </p> <p><font size="2"></font></p> <p><font size="2">As you'd expect, &quot;<em>Deploy application from</em>&quot; is the location on your desktop computer where the .Net Compact Framework application executable you'd like to deploy resides.&#xA0; The &quot;<em>Application</em>&quot; field is the location on the device you'd like your application deployed to.&#xA0; There is one subtlety in the use of these fields to remember: in the &quot;<em>Deploy application from</em>&quot; field you specify the directory your application resides in, not including the name of the executable itself.&#xA0; In the &quot;<em>Application</em>&quot; field you specify the fully qualified name of the destination on device, including executable name.&#xA0; </font></p> <p><font size="2">For example, say I'd like RPM to deploy the file stored on my desktop computer at <font face="Courier New">c:\temp\neilyoung\archives\riverboat.exe</font> to the <font face="Courier New">\program files\sjp</font> directory on my device.&#xA0; The values of the two fields would be:</font></p> <p><font size="2"><img id="id" src="http://farm3.static.flickr.com/2003/1766175967_ae6af26138_o.jpg" /> </font></p> <p>&#xA0;</p> <p><font size="2">This feature can only be used to deploy applications consisting of a single file.&#xA0; If your application contains one executable file and several dlls you'll still have to deploy your application manually.</font></p> <p><font size="2">We hope these improvements make RPM an even better tool.&#xA0; As always, please keep the feedback coming.</font></p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=5697670" width="1" height="1">The CLRProfiler for the .Net Compact Framework, Part II: Histograms and "Show who Allocated"http://blogs.msdn.com/b/stevenpr/archive/2007/10/18/the-clrprofiler-for-the-net-compact-framework-part-ii-histograms-and-show-who-allocated.aspxThu, 18 Oct 2007 20:22:31 GMT91d46819-8472-40ad-a661-2c78acb4018c:5514436stevenpr7http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=5514436http://blogs.msdn.com/b/stevenpr/archive/2007/10/18/the-clrprofiler-for-the-net-compact-framework-part-ii-histograms-and-show-who-allocated.aspx#comments<p><font size="2">Yesterday I started a series of posts on how the use the CLRProfiler for the .Net Compact Framework.&#xA0; The <a href="http://blogs.msdn.com/stevenpr/archive/2007/10/17/the-clrprofiler-for-the-net-compact-framework-part-1-getting-started.aspx">first post</a> contained the basic information you need to get started.&#xA0; I described how to install the profiler, launch an application on the device, and collect profiling data.</font></p> <p><font size="2">In order to direct the discussion, I've written a sample application that exhibits a performance problem that is surprisingly easy to fall into.&#xA0; Throughout these posts I'll show you how to use the profiler to diagnose the problem.&#xA0; To refresh your memory, the sample application is a basic game and the performance problem is that the main windows paints way too slowly.</font></p> <p><font size="2">After I stopped profiling the game in the first post, following summary page was displayed.&#xA0; </font>&#xA0;<img id="id" src="http://farm3.static.flickr.com/2366/1607249692_781068c831.jpg" /> </p> <p><font size="2"><font size="2">In this post I'll use some of the histograms to begin diagnosing our performance problem.</font></font></p> <h1>Histograms</h1> <p><font size="2">The first thing that stands out at me when looking at the summary form is the amount of managed data I'm creating.&#xA0; While profiling the painting portion of my application I generated over 6MB of managed objects.&#xA0; That's clearly way too much for a relatively simple operation like painting my main window.&#xA0; My first step in determining what's going on is to get some basic statistics about the objects my application is using.&#xA0; For example, I'm interested in which objects I'm creating, how many of them there are and how long they live.&#xA0; This data can be obtained by looking at some of the histograms the profiler offers.</font></p> <p><font size="2">I can choose to view a histogram for all objects created as my application ran or only for those objects that were in the GC heap when my application exited.&#xA0; In my scenario I need to look at all objects.&#xA0; If I were to only look at the objects alive at the end of the run I may miss some important trend that occurred earlier on.</font></p> <p><font size="2">Clicking the &quot;<em>Histogram</em>&quot; button next to the &quot;<em>Allocated Bytes</em>&quot; value displays the following graph:</font>&#xA0;</p> <p></p> <p><font size="2"></font></p> <p><font size="2"></font></p> <font size="2"><img id="id" src="http://farm3.static.flickr.com/2116/1618435871_825a99788d.jpg" /> </font> <p></p> <p><font size="2">The histogram form has two panes. The pane on the right describes how many instances of each type of object were created and the total size of those instances.&#xA0; The pane on the left graphs type instances by size.&#xA0; The color coding next to the types in the right pane matches the bars in the left pane which show the relative amounts of objects created.</font></p> <p><font size="2">A quick glance at this form helps narrow my suspicions about what's causing my performance issue.&#xA0; As you can see, about 97% of the objects I created were of type <font face="Courier New">Box.Block</font> as indicated by the red box on the right hand pane and the red bar in the left hand pane.&#xA0; I can also see that each instance of <font face="Courier New">Box.Block</font> is relatively small at an average size of 136 bytes (see the right hand pane).</font></p> <p>&#xA0;</p> <h1>Who Allocated all those Objects?</h1> <p><font size="2">Now that I know the majority of my objects are instances of <font face="Courier New">Box.Block</font>, I'd like to see where in my application those instances are getting created.&#xA0; </font></p> <p><font size="2">To determine the source of my allocations I can right-click on the bar that represents <font face="Courier New">Box.Block</font> in the histogram and select &quot;<em>Show Who Allocated</em>&quot; (the bar turns black when selected):</font></p> <p><img id="id" src="http://farm3.static.flickr.com/2034/1621134688_0a16602c4b.jpg" /> </p> <p><font size="2">Doing so brings up a window referred to as an Allocation Graph:</font></p> <p><font size="2"><img id="id" src="http://farm3.static.flickr.com/2279/1619717659_ec0f0d62b3.jpg" /> </font></p> <p><font size="2"></font></p> <p><font size="2">The Allocation Graph traces the flow of every call that allocated an instance of <font face="Courier New">Box.Block</font>.&#xA0; I typically interpret this graph starting with the rightmost node.&#xA0; This node represents all instances of <font face="Courier New">Box.Block</font> in the system.&#xA0; Stepping back one level to the left we see two nodes representing methods that created instances of <font face="Courier New">Box.Block</font>: <font face="Courier New">Form1.RotateGameBlocks</font> and <font face="Courier New">Form1.InitializeGameBlocks</font>. The data in these nodes tell us that 75% of the <font face="Courier New">Block</font>s were created in <font face="Courier New">RotateGameBlocks</font> and 25% were created in <font face="Courier New">InitializeGameBlocks</font>.&#xA0; Notice that the width of the lines connecting the nodes represents the percentage of instances that call created.</font></p> <p><font size="2">Now that I know where my objects are coming from I can dig into my code to see what's going on.&#xA0; </font></p> <p><font size="2">In some scenarios, the information we've learned so far may be all that we need to fix the problem.&#xA0; However, there are a few more pieces of data that may be required in some cases.&#xA0; For example, it may be useful to know the times at which <font face="Courier New">Blocks</font> were created and destroyed.&#xA0; Also, if <font face="Courier New">RotateGameBlocks</font> and <font face="Courier New">InitializeGameBlocks</font> are long, complicated methods, we may need to know the exact calls within those methods that caused the allocations.&#xA0; I'll describe how to get this information in future posts.</font></p> <p><font size="2"></font></p> <p><font size="2">Thanks,</font></p> <p><font size="2">Steven</font></p> <p>This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights</p><img src="http://blogs.msdn.com/aggbug.aspx?PostID=5514436" width="1" height="1">DiagnosticsThe CLRProfiler for the .Net Compact Framework, Part 1: Getting Startedhttp://blogs.msdn.com/b/stevenpr/archive/2007/10/17/the-clrprofiler-for-the-net-compact-framework-part-1-getting-started.aspxThu, 18 Oct 2007 04:28:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:5502740stevenpr13http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=5502740http://blogs.msdn.com/b/stevenpr/archive/2007/10/17/the-clrprofiler-for-the-net-compact-framework-part-1-getting-started.aspx#comments&nbsp;<A href="http://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx" mce_href="http://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">Version 3.5 of the .Net Compact Framework</SPAN></A><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> </SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">contains a new memory profiler called the CLRProfiler.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The CLRProfiler is a great tool for looking into the details of how your application is allocating and using managed objects.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>For example, the profiler allows you to look at the contents of the GC heap at any point in time, provides a historical record of what's going on in the heap, let's you see which calls in your application are allocating which objects and so on.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This level of detail is often needed to diagnose memory-related issues in your device applications.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The Compact Framework's version of the CLRProfiler is an adaptation of the profiler that has been available for the full .Net Framework for some time.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN></SPAN>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">In this series of posts I'll walk you through the primary features of the CLRProfiler for the .Net Compact Framework.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The profiler contains numerous ways to analyze data about the GC heap so instead of briefly touching on all of them, I'll go into depth on the views I've found most useful.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN></P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">We'll be looking at the profiler by way of an example, as I've found that learning a new tool is often easier if you have a specific problem to solve rather than just looking at the tool's features without any context.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>If you'd like more information on a view that I don't cover here you can read the <A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=a362781c-3870-43be-8926-862b40aa0cd0&amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=a362781c-3870-43be-8926-862b40aa0cd0&amp;DisplayLang=en">document that ships with the full Framework's version of the profiler</A>.</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Verdana"><STRONG>Our Sample</STRONG></P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">The sample I'll use to describe the profiler is the beginnings of a game I started to write using the Compact Framework.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>All the game currently does is allow you to start a new game and to rotate a set of blocks on the screen.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Here's a simple view of the application:</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/1605122889/"><IMG height=559 alt=prof1 src="http://farm3.static.flickr.com/2364/1605122889_08f14f38c7_o.jpg" width=371></A>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P><FONT face=Verdana>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">The performance problem I'm having with this game involves my drawing logic.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The blocks on the screen draw very slowing.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>On my Dell Axim I can literally see each column of blocks paint individually.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Throughout these posts I'll use the CLRProfiler to figure out what I can do to make my game paint more quickly.</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Verdana"><STRONG>Launching an Application with the CLRProfiler</STRONG></P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">The CLRProfiler ships in the <A href="http://www.microsoft.com/downloads/details.aspx?familyid=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;displaylang=en">.Net Compact Framework Power Toys</A> package.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>After installing the Power Toys you can find the CLRProfiler executable (NetCFClrProfiler.exe) in the bin directory of the .Net SDK.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>On my machine that directory is c:\Program Files\Microsoft.Net\SDK\CompactFramework\v3.5\bin.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The Power Toys setup program also adds a menu item for the profiler to the Windows Start menu.</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">The main window of the profiler is strikingly simple:</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/1606427830/"><IMG height=171 alt=prof2 src="http://farm3.static.flickr.com/2271/1606427830_e2a1bdfc80_o.jpg" width=327></A>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">Through this main window you can start and stop applications, take snapshots of the GC heap, and control various profiling options.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>These options include control over whether profiling is currently active and whether allocations, calls or both are logged.</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">Clicking the "<EM>Start Application</EM>…" button displays the following form:</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/1607249510/"><IMG height=213 alt=prof3 src="http://farm3.static.flickr.com/2021/1607249510_6d7c969551_o.jpg" width=641></A>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P></FONT><FONT face=Verdana>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">On this form you enter the name of the device you'd like to connect to, the fully qualified path to the device executable you'd like to profile, and any command line parameters to be passed to the application.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The CLRProfiler supports profiling applications on devices connected either over ActiveSync or TCP/IP.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>You can also profile applications running on emulators.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The profiler supports the same types of devices that<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>the <A href="http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx">.Net Compact Framework Performance Monitor</A> does(in fact, the device selection and connectivity mechanisms are shared between the two tools).</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in"><SPAN style="FONT-FAMILY: Verdana">In my example I have a device connected over ActiveSync and the name of my application is </SPAN><SPAN style="FONT-FAMILY: 'Courier New'">box.exe</SPAN><SPAN style="FONT-FAMILY: Verdana">.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Selecting "<EM>Connect</EM>" from the launch dialog starts the application on device and begins profiling.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>At this point just run your application as you normally would.<SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>The CLRProfiler causes your application to run much slower than normal.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>In order to speed up the debugging process you can turn profiling on and off for different sections of your application using the "<EM>Profiling active</EM>" checkbox on the profiler's main form.</SPAN></P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">When you're done profiling your application, you can stop it either by selecting the "<EM>Kill Application</EM>" button on the main form of the CLRProfiler or by just closing the application directly on the device.</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Verdana"><STRONG>The Summary Form</STRONG></P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">After your application exits the CLRProfiler displays the following summary form:</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/1607249692/"><IMG height=263 alt=prof4 src="http://farm3.static.flickr.com/2366/1607249692_781068c831.jpg" width=500></A>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P></FONT><FONT face=Verdana>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">The summary form provides some general statistics about the use of managed memory as your application ran:</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<UL style="MARGIN-TOP: 0in; MARGIN-BOTTOM: 0in; MARGIN-LEFT: 0.75in; DIRECTION: ltr; unicode-bidi: embed" type=circle>
<LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle"><SPAN style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; FONT-FAMILY: Verdana">Heap Statistics.</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> The statistics displayed in this group box describe the total size of the objects in the managed heap.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The "</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-STYLE: italic; FONT-FAMILY: Verdana">Allocated Bytes"</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> value counts the total size of allocations made as the application was running.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>When the Compact Framework garbage collector detects significant fragmentation in the heap, it will compact it.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The "</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-STYLE: italic; FONT-FAMILY: Verdana">Relocated Bytes</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">" value shows how many bytes the garbage collector moved around during compaction.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>"</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-STYLE: italic; FONT-FAMILY: Verdana">Final Heap Bytes</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">" shows the size of the managed heap when the application exited and "</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-STYLE: italic; FONT-FAMILY: Verdana">Objects Finalized</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">" is what you'd expect: the number of objects that had finalizers to run.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Note that the Heap Statistics group also provides a count of critical finalizers run.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The .Net Compact Framework doesn't have the notion of critical finalization so this value will always be 0.<SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN></SPAN></LI></UL>
<P style="FONT-SIZE: 10pt; MARGIN: 0in 0in 0in 0.75in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in 0in 0in 0.75in; FONT-FAMILY: Verdana">There are several buttons in this box that launch viewers that allow you to analyze data in various ways.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>You can view data in histograms based on object size, age, address and so on.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I'll describe most of these views in detail in subsequent posts.</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in 0in 0in 0.75in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<UL style="MARGIN-TOP: 0in; MARGIN-BOTTOM: 0in; MARGIN-LEFT: 0.75in; DIRECTION: ltr; unicode-bidi: embed" type=circle>
<LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle"><SPAN style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; FONT-FAMILY: Verdana">Garbage Collection Statistics.</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> This group box tells you how many garbage collections occurred while your application was being profiled and how many of those collections were induced by calls to </SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">GC.Collect</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The "<EM>Timeline</EM>" button enables you to see how the contents of the GC heap changes over time.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I think this is one of the coolest views.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I'll describe it in great detail in a subsequent post.</SPAN></LI></UL>
<P style="FONT-SIZE: 10pt; MARGIN: 0in 0in 0in 0.75in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<UL style="MARGIN-TOP: 0in; MARGIN-BOTTOM: 0in; MARGIN-LEFT: 0.75in; DIRECTION: ltr; unicode-bidi: embed" type=circle>
<LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle"><SPAN style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; FONT-FAMILY: Verdana">GC Handle Statistics.</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> The GC Handles group box shows you how many handles were created and destroyed while your application ran.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Keep in mind that the Compact Framework CLR creates GCHandles under the covers as it executes your application so all of the handles you see here aren't likely to have been created explicitly by you.</SPAN></LI></UL>
<P style="FONT-SIZE: 10pt; MARGIN: 0in 0in 0in 0.75in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<UL style="MARGIN-TOP: 0in; MARGIN-BOTTOM: 0in; MARGIN-LEFT: 0.75in; DIRECTION: ltr; unicode-bidi: embed" type=circle>
<LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle"><SPAN style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; FONT-FAMILY: Verdana">Profiling Statistics.</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> The CLRProfiler enables you to take snapshots of the GC heap as your application is running.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I didn't do this while profiling my application, but if I would have I would be able to choose a snapshot from the dropdown and view it.</SPAN></LI></UL>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">Getting back to our example, there are several pieces of data on this form that concern me, or are unexpected.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The key to analyzing performance data such as this is not just looking at the raw values, but in interpreting the values in the context of what your application was doing as it was being profiled.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>For example, I profiled the time my application spent painting, yet I see that 5 garbage collections occurred and I created over 6 MB worth of objects.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This data leads me to believe that I'm making the garbage collector work harder than it should for my scenario.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Clearly there shouldn't be so much activity going on in the managed heap while I'm painting boxes on the screen!</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">In my next post, we'll use some of the histogram views to see how many objects my application is creating and of what type they are.</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">Thanks,</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana">Steven</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana" mce_keep="true">&nbsp;</P>
<P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana"><SPAN lang=EN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Rockwell','serif'; mso-ansi-language: EN">This posting is provided "AS IS" with no warranties, and confers no rights.</SPAN></P></FONT><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=5502740" width="1" height="1">DiagnosticsWrite your own GC Heap Viewer for the .Net Compact Frameworkhttp://blogs.msdn.com/b/stevenpr/archive/2007/09/21/write-your-own-gc-heap-viewer-for-the-net-compact-framework.aspxFri, 21 Sep 2007 19:52:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:5035606stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=5035606http://blogs.msdn.com/b/stevenpr/archive/2007/09/21/write-your-own-gc-heap-viewer-for-the-net-compact-framework.aspx#commentsThe last few versions of the <a class="" href="http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx" mce_href="http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx">Remote Performance Monitor</a> enable you to <a class="" href="http://blogs.msdn.com/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspx" mce_href="http://blogs.msdn.com/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspx">view snapshots of the GC heap on demand</a>.&#xA0; The view of the heap presented by RPM is oriented around finding managed memory leaks.&#xA0; Specifically, the data is organized so that it's easy to see which GC root is responsible for keeping a given object instance alive.&#xA0; <p>We hope the views are well organized and easy to understand, but if you find they don't suite your needs for any reason you can write your own tool to analyze and display the heap data.&#xA0; For example, maybe you want a fancier graphical representation, or you want a view tailored to a scenario other than finding memory leaks. </p> <p>You can't currently plug your new UI directly into RPM but you can save the heap snapshots to a file and create your own tool to view the data.</p> <p>In this post I'll briefly describe how to save the heap data then I'll provide the details of the file format.</p> <h3>Saving a GC Log</h3> <p>Saving a snapshot of the GC heap to a file is easy: Given an open view, just select the &quot;Save&quot; option from the &quot;File&quot; menu:</p> <a title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/1418622344/" mce_href="http://www.flickr.com/photos/stevenjpr/1418622344/"><img height="440" alt="save" src="http://farm2.static.flickr.com/1074/1418622344_a480d5104e_o.jpg" width="662" mce_src="http://farm2.static.flickr.com/1074/1418622344_a480d5104e_o.jpg" /></a> <p>You'll also be prompted to save any unsaved views when you close them.</p> <h3>The GC Log File Format</h3> <p>GC heap dump files are text files that include information for every object present in the GC heap at the time the heap dump was generated using RPM.&#xA0; </p> <p>Each line in the text file contains one record.&#xA0; There are 5 different types of records:</p> <ul type="disc"> <li><b>AppDomain record.</b> Identifies the application domain for which a dump file applies. </li> <li><b>Type record.</b> Describes a type present in the heap. </li> <li><b>Object record.</b> Describes an instance of a type present in the heap. </li> <li><b>Root record.</b> Describes a root instance. </li> <li><b>End AppDomain record.</b> Marks the end of the dump file.</li> </ul> <p mce_keep="true">&#xA0;</p> <p>Each record contains a number of elements separated by spaces.&#xA0; The first element in each line indicates the record type.&#xA0; Here's a portion of a dump file:</p> <p><b>Note</b>: This example is intended to show format only - it's likely not semantically accurate.</p> <p>a 2 bubblecs.exe</p> <p>t 2 System.RuntimeType</p> <p>o 7c79f 2 64</p> <p>t 1 System.NullReferenceException</p> <p>o 7cb42 2 64</p> <p>o 1ce004 1 18</p> <p>t 3 System.OutOfMemoryException</p> <p>o 1ce056 1d 118 1ce11f 1ce14c 1ce079 1ce113 1ce116 1ce267 1ce26a 1ce26d</p> <p>r 22c81b 5 0</p> <p>o 22c81e 1b 24</p> <p>r 22c81e 5 0</p> <p>o 22c823 1b 28</p> <p>r 22c823 5 0</p> <p>c bubblecs.exe</p> <p mce_keep="true">&#xA0;</p> <h4>AppDomain Record</h4> <p>An AppDomain record initiates a section of the file pertaining to a particular application domain.&#xA0; Within that section is all the type, object and root information for the managed objects in that application domain.&#xA0; All AppDomain records are closed with a corresponding End AppDomain record.</p> <p>The AppDomain record has 4 elements: </p> <ul type="disc"> <li><b>The letter &quot;a&quot;.</b> Identifies the record as an application record. </li> <li><b>Version number.</b> A number used to track the file format of the dump file itself.&#xA0; In the current releases this number will always be &quot;2&quot;. </li> <li><b>AppDomain Name.</b> The name of the application domain from which this dump file was generated.&#xA0; This is typically the name of the exe that was run in the app domain. </li> <li><b>Timestamp.</b> The time at which the heap dump was take.&#xA0; RPM obtains this number by calling the WinCE API GetTickCount.</li> </ul> <p mce_keep="true">&#xA0;</p> <p>Example:</p> <p>a 2 NHLSchedule.exe 444d20df</p> <p mce_keep="true">&#xA0;</p> <h4>Type Record</h4> <p>Type records identify types in the GC heap.&#xA0; Each type record contains 3 elements:</p> <ul type="disc"> <li><b>The letter &quot;t&quot;.</b> Identifies the record as a type record. </li> <li><b>Type ID.</b> A unique numerical identifier for this type.&#xA0; This identifier is used to tie object instances to their types (see description of Object Records below). </li> <li><b>Type name.</b>&#xA0; The fully qualified name of the type.</li> </ul> <p mce_keep="true">&#xA0;</p> <p>Example:</p> <p>t a1 Western.Pacific.SanJoseSharks</p> <p>Note:</p> <ul type="disc"> <li>Type identifiers are not guaranteed to be unique across dump files.&#xA0; For example, the identifier for the &quot;SanJoseSharks&quot; type in the example above isn't guaranteed to be a1 in a different dump taken from the same application at a different point in time.</li> </ul> <h4>Object Record</h4> <p>Object records describe specific instances of types in the GC heap.&#xA0; Object records have a variable number of elements.&#xA0; The first 4 elements are required:</p> <ul type="disc"> <li><b>The letter &quot;o&quot;.</b> Identifies the record as an object record. </li> <li><b>Object ID.</b> A unique numerical identifier for this object.&#xA0; </li> <li><b>Type ID.</b> The identifier for the type of this object. </li> <li><b>Object size.</b> The size in bytes for this instance.</li> </ul> <p>In addition to these required elements, object records will have a variable number of additional elements describing the instances that the object references.</p> <ul type="disc"> <li><b>Referenced Object IDs.</b> The identifiers for all objects that this object references.&#xA0; </li> </ul> <p mce_keep="true">&#xA0;</p> <p>An example with referenced object ids:</p> <p>o 1c15d2 3 1c 1c15db 1c15d8 1c15d5</p> <p>Notes:</p> <ul type="disc"> <li>Object identifiers are not guaranteed to be unique across dump files.&#xA0; This point is important for tools writers:&#xA0; It is not possible to develop tools that identify trends across dump files because a given object instance in one dump isn't guaranteed to have the same identifier in a later dump of the same heap. </li> <li>The type record corresponding to a particular object record is not guaranteed to precede the object record in the dump file.</li> </ul> <h4>Root Record</h4> <p>Root records identify GC roots.&#xA0; Each root record contains 4 required elements:</p> <ul type="disc"> <li><b>The letter &quot;r&quot;.</b>&#xA0; Identifies the record as a root record. </li> <li><b>Object ID.</b> The identifier of the object that is this root. </li> <li><b>Root kind.</b> The reason this object instance is a root.&#xA0; One of the following values:</li> </ul> <blockquote> <p><b>1</b> The object instance is a local variable.</p> <p><b>2 </b>The object instance is on the finalizer queue waiting for its finalizer to be run.&#xA0; After the finalizer is run the object will be collected during the next GC.</p> <p><b>3</b> A GC handle exists which refers to the object instance (i.e System.Runtime.InteropServices.GCHandle)</p> <p><b>4</b> The object instance is a static variable.</p> <p><b>5</b> The object instance is a root specific to the Compact Framework's GC implementation.&#xA0; Examples include interned strings or class descriptions. </p> <p><b>0</b> The object instance is rooted internally by the Compact Framework. Examples include object instances for application domains, assemblies, exceptions and so on.</p> </blockquote> <ul> <li><b>Root flags.</b> A set of flags providing more information about the root:</li> </ul> <blockquote> <p><b>0x1.</b> The root is pinned.&#xA0; There are several cases in which a root may be pinned.&#xA0; For example, the root may refer to managed objects that have been passed out to native code via PInvoke or COM interop, the root may be referenced by a GCHandle created with a GCHandleType of Pinned or a pointer in unsafe code points to the root.&#xA0; </p> <p>The .Net Compact Framework CLR may also pin objects on your behalf as it runs your application.&#xA0; The CLR will pin an object if it places a reference to that object in a register or refers to that object from the stack.&#xA0; An object will also be pinned if a local variable or method argument points to a field within the object.&#xA0; The CLR doesn't pin objects very often, but if one of the more obvious reasons don't explain why an object is pinned, it may be because of one of these &quot;hidden&quot; cases.</p> <p><b>0x2.</b> A GCHandle whose GCHandleType is Weak refers to the object.</p> <p><b>0x4.</b> The object is pointed to by a pointer in unsafe code or has a local variable or method argument points to a field within the object.</p> </blockquote> <p mce_keep="true">If the root kind is static, the root record will have an additional element:</p> <ul type="disc"> <li><b>Root container.</b>&#xA0; The identifier of the type the static variable is contained in.</li> </ul> <p mce_keep="true">Here's a root record with the additional root container element:</p> <p>r b2753 4 0 13c</p> <p mce_keep="true"><b></b>&#xA0;</p> <p mce_keep="true"></p> <h4>End AppDomain Record</h4> <p>End AppDomain records close the section initiated by a corresponding AppDomain record.&#xA0;&#xA0; End AppDomain records have three elements:</p> <ul type="disc"> <li><b>The letter &quot;c&quot;.</b> Identifies the record as an end record </li> <li><b>Application Name.</b>&#xA0; The name of the application from which this dump file was generated.&#xA0; This name matches the name in the application record at the beginning of the file. </li> <li><b>Timestamp.</b>&#xA0; The timestamp from the corresponding AppDomain record.</li> </ul> <p mce_keep="true">&#xA0;</p> <p mce_keep="true">Thanks,</p> <p mce_keep="true">Steven</p> <p mce_keep="true"><span lang="EN" style="font-size: 10pt; line-height: 115%; font-family: &#x27;Rockwell&#x27;,&#x27;serif&#x27;; mso-ansi-language: en">This posting is provided &quot;AS IS&quot; with no warranties, and confers no rights.</span></p><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=5035606" width="1" height="1">.Net Compact Framework: “Hey, what happened to the diagnostic tools?”http://blogs.msdn.com/b/stevenpr/archive/2007/09/12/net-compact-framework-hey-what-happened-to-the-diagnostic-tools.aspxThu, 13 Sep 2007 03:33:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:4886477stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=4886477http://blogs.msdn.com/b/stevenpr/archive/2007/09/12/net-compact-framework-hey-what-happened-to-the-diagnostic-tools.aspx#comments<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><FONT face=Calibri>If you’ve installed the Beta2 version of Orcas you may have noticed that the NetCF diagnostic tools&nbsp;(RPM, CLRProfler, ...)&nbsp;are missing.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Don’t worry, these haven’t been cut from Orcas, they will just be distributed via the web in a separate “power toys” pack.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>A CTP of these tools is now available at: <SPAN style="COLOR: #1f497d"><A href="http://www.microsoft.com/downloads/details.aspx?familyid=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;displaylang=en">http://www.microsoft.com/downloads/details.aspx?familyid=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;displaylang=en</A></SPAN> .<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This CTP works with Orcas Beta2.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><FONT face=Calibri>We intend to distribute the final Power Toys release at the same time that Orcas ships.<o:p></o:p></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><FONT face=Calibri>Thanks,<o:p></o:p></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><FONT face=Calibri>Steven</FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><FONT face=Calibri></FONT></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><FONT face=Calibri><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Tahoma','sans-serif'; mso-ansi-language: EN-US; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN lang=EN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Rockwell','serif'; mso-ansi-language: EN">This posting is provided "AS IS" with no warranties, and confers no rights.</SPAN></SPAN>&nbsp;<o:p></o:p></FONT></FONT></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=4886477" width="1" height="1">Diagnostics.Net Compact Framework Performance Webcasthttp://blogs.msdn.com/b/stevenpr/archive/2007/08/14/net-compact-framework-performance-webcast.aspxTue, 14 Aug 2007 20:53:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:4387014stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=4387014http://blogs.msdn.com/b/stevenpr/archive/2007/08/14/net-compact-framework-performance-webcast.aspx#comments<P>Last week I did an MSDN webcast on writing high performing device applications using the .Net Compact Framework.&nbsp; The webcast contains both in depth information on the internal workings of the Compact Framework and a set of tips and tricks for optimizing performance in everything from user interface to collections to networking.&nbsp; Here's the URL<SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Arial','sans-serif'">: </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Arial','sans-serif'"><A title=http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032345907&amp;Culture=en-US href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032345907&amp;Culture=en-US" mce_href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032345907&amp;Culture=en-US">http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032345907&amp;Culture=en-US</A>&nbsp;.</SPAN></P>
<P>Also, I had promised those viewing the webcast live that I would post the "generics" slide without the performance numbers overlaying the code.&nbsp; Here it is:&nbsp;</P>
<P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/1117072123/"><IMG height=368 alt=Generics src="http://farm2.static.flickr.com/1268/1117072123_980031a705_o.jpg" width=492></A></P>
<P mce_keep="true">&nbsp;</P>
<P>Thanks,</P>
<P>Steven</P>
<P><FONT size=1>Disclaimer(s):<BR>This posting is provided "AS IS" with no warranties, and confers no rights.</FONT></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=4387014" width="1" height="1">NetCF GeneralUsing the .NetCF Remote Performance Monitor to find memory leaks: A real world examplehttp://blogs.msdn.com/b/stevenpr/archive/2007/03/23/using-the-netcf-remote-performance-monitor-to-find-memory-leaks-a-real-world-example.aspxFri, 23 Mar 2007 20:32:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:1938492stevenpr0http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=1938492http://blogs.msdn.com/b/stevenpr/archive/2007/03/23/using-the-netcf-remote-performance-monitor-to-find-memory-leaks-a-real-world-example.aspx#comments<P>A few weeks ago I posted an entry describing <A class="" href="http://blogs.msdn.com/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspx" mce_href="http://blogs.msdn.com/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspx">how to use the .Net Compact Framework Remote Performance Monitor to find managed memory leaks</A>.&nbsp; The other day I ran across a post from <A class="" href="http://blogs.msdn.com/controlpanel/blogs/www.satter.org" mce_href="http://blogs.msdn.com/controlpanel/blogs/www.satter.org">Rabi&nbsp;Satter</A>&nbsp;describing how he used to tool to solve a critical leak for one of his customers.&nbsp; His&nbsp;real world experience&nbsp;provides a much more complete memory leak example than my original post did.&nbsp; Check it out: <SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Tahoma','sans-serif'; mso-ansi-language: EN-US; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">. <A href="http://www.satter.org/2007/03/thank_god_for_c.html">http://www.satter.org/2007/03/thank_god_for_c.html</A></SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Tahoma','sans-serif'; mso-ansi-language: EN-US; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Thanks,</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Tahoma','sans-serif'; mso-ansi-language: EN-US; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Steven</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Tahoma','sans-serif'; mso-ansi-language: EN-US; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN lang=EN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Rockwell','serif'; mso-ansi-language: EN">This posting is provided "AS IS" with no warranties, and confers no rights.</SPAN></SPAN></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=1938492" width="1" height="1">GCDiagnosticsFinding Managed Memory leaks using the .Net CF Remote Performance Monitorhttp://blogs.msdn.com/b/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspxThu, 08 Mar 2007 21:01:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:1838215stevenpr11http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=1838215http://blogs.msdn.com/b/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspx#comments&nbsp;
<P><A class="" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=aea55f2f-07b5-4a8c-8a44-b4e1b196d5c0&amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=aea55f2f-07b5-4a8c-8a44-b4e1b196d5c0&amp;displaylang=en">Service Pack 2 of the .Net Compact Framework V2.0</A> includes some new features in the <A href="http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx">Remote Performance Monitor</A> aimed at finding memory leaks in the managed heap.&nbsp; These features allow you to take snapshots of the GC heap at any point in time and view the relationships between the live object instances in the heap.&nbsp; You can also compare multiple snapshots over time in order to spot allocation trends in your application as it executes.</P>
<P>In this post I'll walk you through the basic capabilities of the heap viewer features and provide an example to illustrate the type of problem the heap viewer is intended to solve. </P>
<H2>But Managed Applications Can't Leak Memory, Right?</H2>
<P>Because of the automatic memory management features in .Net it is tempting to believe that managed applications will never have memory leaks.&nbsp; While it is true that the garbage collector will always free objects that are no longer referenced, it is possible to hold on to an object longer than you intend to, thereby preventing it from being collected and essentially creating a leak.&nbsp; </P>
<P>Remember that the GC will not collect any object that is referenced by a "root" such as a static variable, a stack-based variable in the currently executing method and so on.&nbsp; So even if you're done using an object, if it is not detached from the root that is keeping it alive it won't be collected.&nbsp; </P>
<P>In the vast majority of cases, making sure an object is no longer referenced when you are done with it requires no additional work from the programmer.&nbsp; For example, when a method exits, all references held by the method's locals go out of scope and therefore are no longer attached to a root.&nbsp; However, there are a few relatively common cases in which more thought is required to make sure you're detaching an instance from its root(s).&nbsp; A few examples:</P>
<UL>
<LI><B>Event handlers.</B> Connecting an event handler defined in one object to an event defined by another object creates a dependency between those two objects. If you forget to detach the handler (i.e using -=) when you're done, it's easy to create a dependency that might cause the object in which the handler is defined to leak.</LI>
<LI><B>Static variables.</B> Consider a case in which you use a static variable to hold an array of objects. Every object in that array is rooted by the static. If you forget to explicitly remove an object from the array when you are done with it, it will not be collected until the static itself is.</LI></UL>
<P>More details on these scenarios, and examples of others, can be found by searching the web for something like ".Net memory leaks"</P>
<H3>How do I know that I have a memory leak?</H3>
<P>Memory leaks typically manifest themselves in obvious ways: your application starts seeing OutOfMemoryExceptions, performance degrades over time and so on.&nbsp; Your application likely has a leak if the amount of memory used by the GC continues to grow over time. </P>
<P>The best way to track the amount of memory used to store objects in the GC heap is to monitor the "<I>Managed Bytes in use After GC</I>" counter in RPM.&nbsp; Graphing the value of this counter over time using Perfmon is the easiest way to determine whether the heap is continually growing.</P>
<H2>Capturing Snapshots of the GC Heap</H2>
<P>Now that we've seen some simple examples of memory leaks, it's easy to imagine the data that would be useful in tracking leaks down:</P>
<UL>
<LI>At any given point in time, which objects are alive in the GC heap?</LI>
<LI>For each instance, what is the GC root that is causing it to stay alive?</LI>
<LI>Over time, which types have an increasing number of instances?</LI></UL>
<P>The rest of this post describes how to use the heap snapshot feature in Remote Performance Monitor to gather this information.</P>
<P>Let's start by looking at how to use RPM to capture a snapshot of the heap.&nbsp; First, launch an application as you always have using the "Live Counters..." menu option (if you haven't used RPM before the following post will help get you started: <A href="http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx">http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx</A> ).</P>
<P>After your application launches, the "View GC Heap" button on the bottom toolstrip is enabled as shown in the following figure:</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/414784447/"><IMG height=517 alt=gcheap1 src="http://farm1.static.flickr.com/183/414784447_9b47b5153f_o.jpg" width=699></A>
<P>Each time you press "View GC Heap" a GC occurs and a new window will open to display the contents of the GC heap after the collection completes.&nbsp; I call this new window the "Roots" view.</P>
<H2>The "Roots" View</H2>
<P>The primary purpose of the roots view is to show the GC root that is causing each object instance to stay alive.&nbsp; Once you've narrowed down the type of instance that is causing the leak (more on how to do this later), you can use the roots view to determine why the instances in question aren't being collected.</P>
<P>The data displayed in the roots view is shown in the following three controls:</P>
<UL>
<LI>The Statistics group</LI>
<LI>The Types table</LI>
<LI>The Root tree</LI></UL><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/414784453/"><IMG height=561 alt=gcheap2 src="http://farm1.static.flickr.com/187/414784453_127da339eb_o.jpg" width=956></A>
<H3>The Statistics Group</H3>
<P>The number of live objects in the heap, and the total size of those objects, is shown in the statistics group.&nbsp; When looking at multiple views, a quick glance at these statistics will tell you how the size of your heap is changing over time.</P>
<H3>The Types table</H3>
<P>The types table shows how many instances of each type are alive in the GC heap.&nbsp; The cumulative size of all instances of each type is also shown.&nbsp; Over time, the data displayed in this table will tell you whether the number of instances of a given type is growing or shrinking.&nbsp; Later, I describe how to use the "comparison view" to easily compare this data across multiple snapshots of the heap.</P>
<P>By default, the types table is sorted by number of instances.&nbsp; You can change the sort order by clicking on the table's column headers.</P>
<P>The check boxes next to the type names show which instances are displayed in the roots tree to the right.&nbsp; By default, the intent is to display the types that are defined by the application itself, not those defined by the .Net Compact Framework.&nbsp; Types with namespaces starting with "Microsoft" or "System" are excluded.&nbsp; You can change which types are shown in the roots tree by selecting the desired boxes and choosing the "Refresh Tree" button.</P>
<H3>The Roots Tree</H3>
<P>Each instance in the GC heap is displayed in the roots tree.&nbsp;&nbsp; Instances are grouped by type (unless there's only one instance of a given type, in which case that instance gets a top-level node of its own).&nbsp; The node for a given instance indicates the size in bytes of that instance along with a unique ID you can use to identify that instance throughout the tree.&nbsp; </P>
<P>By expanding the node for a given instance, you can walk your way up the reference hierarchy to see which root is causing that instance to stay alive.&nbsp; For example, consider the following subtree for an instance of type "Dice":</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/414784457/"><IMG height=136 alt=gcheap3 src="http://farm1.static.flickr.com/161/414784457_b1ceee731d_o.jpg" width=800></A>
<P>This tree shows us that our instance of Dice is referenced by an array of Dice.&nbsp; The array is then referenced by an instance of type Turn which is referenced by Form1.&nbsp; Form1 is a root as indicated by the word "root" and by the red color of the text. </P>
<H2>The "References" View</H2>
<P>The hierarchy shown in the roots view is "upside down" in that you're viewing the instances that reference the instance in question (the referents) .&nbsp; While this is the most useful view for finding leaks, it can also be useful to view the graph of objects a given instance references.&nbsp; Such reference graphs are provided by the "references view".</P>
<P>To view the reference graph for a given instance, right-click the instance in the roots tree and select "Display Object References" (this menu item is also available under the "View" pull down menu):</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/414784463/"><IMG height=561 alt=gcheap4 src="http://farm1.static.flickr.com/173/414784463_5eab810e4e_o.jpg" width=956></A>
<P>The reference view consists of a group that displays some general graph statistics and a tree showing the graph itself.&nbsp; The following screenshot displays the object graph for a main form.&nbsp; The reference graph for this particular form has 207 unique objects and is about 16K in size:</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/414784476/"><IMG height=665 alt=gcheap5 src="http://farm1.static.flickr.com/179/414784476_55a97b7d15_o.jpg" width=565></A>
<H2>Comparing Snapshots of the GC Heap</H2>
<P>You can determine which instances are leaking by taking multiple snapshots of the heap over time and comparing how many instances of each type are present.&nbsp; If the number of instances of a given type unexpectedly increases over time, it's likely that the instances are leaking.&nbsp; The "Comparison" view can help you spot these trends.</P>
<P>You can compare all open heap snapshots for a given application by selecting the "Compare Views..." item from the "View" menu on the roots view of any snapshot.&nbsp; The Comparison view looks like this:</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/414784479/"><IMG height=577 alt=gcheap6 src="http://farm1.static.flickr.com/132/414784479_dadb0b179c_o.jpg" width=926></A>
<P>The Comparison view shows instances counts for all types that appear in all open snapshots.&nbsp; Each row represents a type while each column shows the number of instances of that type that are present in a given snapshot.&nbsp; The snapshot columns are ordered by time to make it easy to spot trends.</P>
<P>The table is sorted based on the delta in the number of instances between snapshots.&nbsp; Those types that had the greatest change in the number of instances appear first, while those that didn't change at all are shown at the bottom.&nbsp; When the number of instances of a type changes from one snapshot to the next, a "+" or "-" sign is shown along with the delta.</P>
<P>Those rows that represent a delta are shown in red.&nbsp; Rows with no change in the number of instances are shown in black.</P>
<H3>Identifying Leaks using the Comparison View</H3>
<P>Memory leaks can be spotted by analyzing the rows in the table that are displayed in red.&nbsp; &nbsp;The types at the top of the table above are all from the .Net Compact Framework base class libraries.&nbsp; As I look at the list it's pretty clear that some sort of UI element is leaking.&nbsp; As I read down the list I eventually get to one of my own types: Players.Stats in this case.&nbsp; The number of instances of Players.Stats increased by 2 each time I took a snapshot.&nbsp; Players.Stats is a dialog box that displays basic statistical information about a player.&nbsp; Given that I create a new one of these each time a certain button is clicked, then let it go out of scope, I didn't suspect that instances of this type were leaking.</P>
<P>Now that I know which type is causing a leak, I can go back to the Roots view to see what GC root is causing my instances of Players.Stats to stay alive.&nbsp; By looking at the referents tree for Players.Stat I can see that my instances are staying alive because I've added an event handler that I've forgotten to "free".&nbsp; This event handler has created a dependency between a button on my main form and my Players.Stats dialog: </P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/414794742/"><IMG height=563 alt=gcheap8 src="http://farm1.static.flickr.com/147/414794742_f42d9925b4_o.jpg" width=789></A>
<P>Armed with this data, I can go back into my code and detach my event handler using -= thereby breaking the dependency between my two forms and fixing my leak.</P>
<H2>Saving Snapshots</H2>
<P>Once you've opened a snapshot you can save it to a file for later analysis.&nbsp; Choose the "Save" item from the File menu to save a snapshot.&nbsp; Choose the "Open-&gt; .gclog file" item from the File menu to view a previously saved shapshot.</P>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">As always, please send any feedback my way...</P>
<P mce_keep="true">Thanks,</P>
<P mce_keep="true">Steven</P>
<P mce_keep="true"><SPAN lang=EN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Rockwell','serif'; mso-ansi-language: EN">This posting is provided "AS IS" with no warranties, and confers no rights.</SPAN></P>
<P mce_keep="true">&nbsp;</P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=1838215" width="1" height="1">Using the .Net Compact Framework Remote Performance Monitor to Optimize your application's memory usagehttp://blogs.msdn.com/b/stevenpr/archive/2007/01/02/using-the-net-compact-framework-remote-performance-monitor-to-optimize-your-application-s-memory-usage.aspxWed, 03 Jan 2007 02:51:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:1401044stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=1401044http://blogs.msdn.com/b/stevenpr/archive/2007/01/02/using-the-net-compact-framework-remote-performance-monitor-to-optimize-your-application-s-memory-usage.aspx#comments<P>The <A class="" href="http://dotnet.sys-con.com/read/issue/827.htm" target=_blank mce_href="http://dotnet.sys-con.com/read/issue/827.htm">November issue of .Net Developers Journal</A>&nbsp;includes a <A class="" href="http://dotnet.sys-con.com/read/315037.htm" mce_href="http://dotnet.sys-con.com/read/315037.htm">new article on using the Remote Performance Montior</A>.&nbsp; In the article I describe how to interpret the various memory-related counters to optimize how your Compact Framework application uses memory on the device.</P>
<P>Thanks,</P>
<P>Steven</P>
<P><SPAN lang=EN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Rockwell','serif'; mso-ansi-language: EN">This posting is provided "AS IS" with no warranties, and confers no rights.</SPAN></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=1401044" width="1" height="1">GCDiagnosticsMore book updates for Customizing the CLRhttp://blogs.msdn.com/b/stevenpr/archive/2006/12/07/more-book-updates-for-customizing-the-clr.aspxThu, 07 Dec 2006 22:24:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:1233949stevenpr2http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=1233949http://blogs.msdn.com/b/stevenpr/archive/2006/12/07/more-book-updates-for-customizing-the-clr.aspx#comments<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">I’ve recently been made aware of two more updates I need to provide for my book on <A href="http://www.microsoft.com/mspress/books/6895.aspx">Customizing the .Net Framework CLR</A>.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>As always, I apologize for any inconvenience these discrepancies may have caused.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">Chapter 2, Page 7.</SPAN></B><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> The table which lists the methods on </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">ICLRRuntimeHost</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> indicates that more information about </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">ExecuteInDomain</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> is available in Chapter 7.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I had not intended to cover this method at all in the book, but the forward reference still exists.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>If you’d like information on </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">ExecuteInDomain</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> I’d be happy to provide you with a sample.<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">Chapter 5, Page 90.</SPAN></B><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">SetAppDomainManagerType</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> method on </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">ICLRControl</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> is used to inform the CLR of the assembly and type that implements your domain manager.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The code sample on page 90 calls </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">SetAppDomainManagerType</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> after the CLR has been initialized by a call to </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">ICLRRuntimeHost::Start</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">:<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><o:p></o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">int main(int argc, wchar_t* argv[])<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">{<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN>// Initialize the CLR using CorBindToRuntimeEx.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This gets us <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>// the ICLRRuntimeHost pointer we’ll need to call Start.<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN>ICLRRuntimeHost *pCLR = NULL;<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>HRESULT hr = CorBindToRuntimeEx(<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>L"v2.0.31113", <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>L"wks",<SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>STARTUP_CONCURRENT_GC, <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>CLSID_CLRRuntimeHost, <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>IID_ICLRRuntimeHost, <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>(PVOID*) &amp;pCLR);<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><o:p><FONT face="Courier New">&nbsp;</FONT></o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>// Start the CLR<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN><B style="mso-bidi-font-weight: normal"><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>hr = pCLR-&gt;Start();<o:p></o:p></B></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><o:p><FONT face="Courier New">&nbsp;</FONT></o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN>// Get a pointer to the ICLRControl interface<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">ICLRControl *pCLRControl = NULL;<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">hr = pCLR-&gt;GetCLRControl(&amp;pCLRControl);<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><o:p><FONT face="Courier New">&nbsp;</FONT></o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">// Call SetAppDomainManagerType to associate our domain manager with <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">// the process<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New">pCLRControl-&gt;SetAppDomainManagerType(<o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 153pt; TEXT-INDENT: -9pt"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New">L”BoatRaceHostRuntime, Version=1.0.0.0, <SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN>PublicKeyToken=5cf360b40180107c, culture=neutral”, <o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>L"BoatRaceHostRuntime.BoatRaceDomainManager"<o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 3.75in; TEXT-INDENT: 0.25in"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New">);<o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">// rest of main() omitted…<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">This is incorrect.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">SetAppDomainManagerType</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"> must be called <B style="mso-bidi-font-weight: normal">before</B> </SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #003399; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'">ICLRRuntimeHost::Start</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Here’ the corrected code sample:<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">int main(int argc, wchar_t* argv[])<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">{<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN>// Initialize the CLR using CorBindToRuntimeEx.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This gets us <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>// the ICLRRuntimeHost pointer we’ll need to call Start.<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN>ICLRRuntimeHost *pCLR = NULL;<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>HRESULT hr = CorBindToRuntimeEx(<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>L"v2.0.31113", <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>L"wks",<SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>STARTUP_CONCURRENT_GC, <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>CLSID_CLRRuntimeHost, <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>IID_ICLRRuntimeHost, <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>(PVOID*) &amp;pCLR);<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><o:p><FONT face="Courier New">&nbsp;</FONT></o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN><SPAN style="mso-tab-count: 1"></SPAN>// Get a pointer to the ICLRControl interface<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">ICLRControl *pCLRControl = NULL;<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">hr = pCLR-&gt;GetCLRControl(&amp;pCLRControl);<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><o:p><FONT face="Courier New">&nbsp;</FONT></o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">// Call SetAppDomainManagerType to associate our domain manager with <o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><SPAN style="COLOR: #003399"><FONT face="Courier New">// the process<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in; TEXT-INDENT: 0.25in"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New">pCLRControl-&gt;SetAppDomainManagerType(<o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 153pt; TEXT-INDENT: -9pt"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New">L”BoatRaceHostRuntime, Version=1.0.0.0, <SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN>PublicKeyToken=5cf360b40180107c, culture=neutral”, <o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>L"BoatRaceHostRuntime.BoatRaceDomainManager"<o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 3.75in; TEXT-INDENT: 0.25in"><B style="mso-bidi-font-weight: normal"><SPAN style="COLOR: #003399"><FONT face="Courier New">);<o:p></o:p></FONT></SPAN></B></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp;</SPAN><o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>// Start the CLR<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New"><SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN><B style="mso-bidi-font-weight: normal"><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>hr = pCLR-&gt;Start();<o:p></o:p></B></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><o:p><FONT face="Courier New">&nbsp;</FONT></o:p></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">// rest of main() omitted…<o:p></o:p></FONT></SPAN></P>
<P class=ProgList style="MARGIN: 0in -59.75pt 3pt 0.75in"><SPAN style="COLOR: #003399"><FONT face="Courier New">}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">Thanks,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'">Steven<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><SPAN lang=EN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Rockwell','serif'; mso-ansi-language: EN">This posting is provided "AS IS" with no warranties, and confers no rights.</SPAN><SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Verdana','sans-serif'"><o:p></o:p></SPAN></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=1233949" width="1" height="1">Custominzing the CLR bookAuto-Deployment of Remote Performance Monitor Device-side Componentshttp://blogs.msdn.com/b/stevenpr/archive/2006/10/31/auto-deployment-of-remote-performance-monitor-device-side-components.aspxWed, 01 Nov 2006 02:35:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:916140stevenpr1http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=916140http://blogs.msdn.com/b/stevenpr/archive/2006/10/31/auto-deployment-of-remote-performance-monitor-device-side-components.aspx#comments<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=Calibri size=3>In my&nbsp;</FONT><A href="http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx"><FONT face=Calibri size=3>earlier post</FONT></A><FONT face=Calibri size=3> on using the .Net Compact Framework Remote Performance Monitor, I describe that you must manually copy two files (netcfrtl.dll and netcflaunch.exe) to your device before you can launch an application to receive performance statistics.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><A href="http://blog.opennetcf.org/ctacke/"><FONT face=Calibri size=3>Chris Tacke</FONT></A><FONT face=Calibri size=3> of </FONT><A href="http://www.opennetcf.org/"><FONT face=Calibri size=3>OpenNetCF.org</FONT></A><FONT face=Calibri size=3> recently got tired of this manual process and wrote a program you can use to automate the deployment of these two files.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Check out: </FONT><A href="http://blog.opennetcf.org/ctacke/PermaLink,guid,793b6c03-496c-4187-a27c-bf369c67d713.aspx"><FONT face=Calibri size=3>http://blog.opennetcf.org/ctacke/PermaLink,guid,793b6c03-496c-4187-a27c-bf369c67d713.aspx</FONT></A><FONT face=Calibri size=3> </FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=Calibri size=3>Thanks for your help Chris,</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=Calibri size=3>Steven</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=Rockwell>This posting is provided "AS IS" with no warranties, and confers no rights</FONT></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=916140" width="1" height="1">DiagnosticsAnalyzing Device Application Performance with the .Net Compact Framework Remote Performance Monitorhttp://blogs.msdn.com/b/stevenpr/archive/2006/04/17/577636.aspxMon, 17 Apr 2006 20:15:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:577636stevenpr59http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=577636http://blogs.msdn.com/b/stevenpr/archive/2006/04/17/577636.aspx#comments<P><FONT face=Verdana size=2>Service Pack 1 of the .Net Compact Framework version 2 (see <A HREF="/netcfteam/archive/2006/04/21/580901.aspx">http://blogs.msdn.com/netcfteam/archive/2006/04/21/580901.aspx</A>) includes a new utility called the .Net Compact Framework Remote Performance Monitor (RPM).&nbsp; The RPM helps you diagnose performance problems in your application by providing a dynamic, graphical view of various runtime performance statistics.&nbsp; The performance statistics displayed by the RPM are those that are present in the ".stat" files in previous versions of the Compact Framework.&nbsp; See David Kline's blog entry "<A href="/davidklinems/archive/2005/12/09/502125.aspx">Monitoring Application Performance...</A>" for a thorough description of all the counters viewable through the RPM.</FONT></P>
<P><FONT face=Verdana size=2>You have two choices when viewing data using RPM.&nbsp; First, you can view the counters in a textual table format using the RPM tool itself, or you can view all the data the RPM gathers using the standard Windows Performance Monitor.</FONT></P>
<P><FONT face=Verdana size=2>This post provides instructions for installing and using the RPM.&nbsp; This tool is a big step forward for .Net Compact Framework developers.&nbsp; For the first time, you'll be able to to use standard performance tools to gain insight into your application's performance as it runs!</FONT></P>
<P><B><FONT face=Verdana size=3>Installation</FONT></B></P>
<P><FONT face=Verdana size=2>The .Net CF Remote Performance Monitor includes some files that reside on the desktop machine and some files that must be present on the device.</FONT></P>
<P><FONT face=Verdana size=2>Installing the desktop components is easy - just run the SP1 setup program.&nbsp; After the installation completes, the RPM executable (</FONT><FONT face="Courier New" color=#000080 size=2>netcfrpm.exe</FONT><FONT face=Verdana size=2>) is placed in the bin directory of Compact Framework SDK.&nbsp; On my machine, this directory is </FONT><FONT face="Courier New" color=#000080 size=2>C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\bin.</FONT></P>
<P><FONT face=Verdana size=2>Installing the device-side components involves manually copying two files from the desktop machine to the device.&nbsp; The SP1 setup program places the device-side files in the same directory as the cab file that matches your processor type and operation system version.&nbsp; I have a Pocket PC 2003 SE device, so my device-side components are installed in </FONT><FONT face="Courier New" color=#000080 size=2>C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\wce400\armv4</FONT><FONT face=Verdana size=2>. The two files you must copy are </FONT><FONT face="Courier New" color=#000080 size=2>netcfrtl.dll </FONT><FONT face=Verdana size=2>and </FONT><FONT face="Courier New" color=#000080 size=2>netcflaunch.exe</FONT><FONT face=Verdana size=2>.&nbsp; Both of these files must be copied to the </FONT><FONT face="Courier New" color=#000080 size=2>\windows directory</FONT><FONT face=Verdana size=2> of your device.</FONT></P>
<DIV style="BORDER-LEFT-COLOR: #800000; BORDER-BOTTOM-COLOR: #800000; BORDER-TOP-STYLE: dotted; BORDER-TOP-COLOR: #800000; BORDER-RIGHT-STYLE: dotted; BORDER-LEFT-STYLE: dotted; BORDER-RIGHT-COLOR: #800000; BORDER-BOTTOM-STYLE: dotted"><B><FONT face=Verdana size=2>Installation Notes for Windows Mobile 5.0 Devices</FONT></B>
<P><FONT face=Verdana size=2>There are two issues you may run into when installing the device-side RPM components on Windows Mobile 5.0 devices.<BR><BR>&nbsp;- Depending on the security configuration chosen by the device manufacturer, you may see a security prompt on the device the first time you launch the RPM. This prompt appears because </FONT><FONT face="Courier New" color=#000080 size=2>netcfrpm.dll</FONT><FONT face=Verdana size=2> is not signed.<BR><BR>- An additional installation step is necessary on Windows Mobile 5.0 devices to provision the device so the RPM can run. Provisioning involves copying the following XML text into a file and using the </FONT><FONT face="Courier New" color=#000080 size=2>rapiconfig</FONT><FONT face=Verdana size=2> utility to send the XML file to the device.<BR><BR>- &lt;wap-provisioningdoc&gt;<BR>&nbsp;&nbsp; - &lt;characteristic type="Metabase"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - &lt;characteristic type="RAPI\Windows\netcfrtl.dll\*"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parm name="rw-access" value="3" /&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parm name="access-role" value="152" /&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 152 maps to "CARRIER_TPS | USER_AUTH | MANAGER"--&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/characteristic&gt;<BR>&nbsp;&nbsp; &lt;/characteristic&gt;<BR>&lt;/wap-provisioningdoc&gt;<BR><BR>For example, if you pasted the above XML text into a file named </FONT><FONT face="Courier New" color=#000080 size=2>rpmprov.xml</FONT><FONT face=Verdana size=2> you'd issue the following command from your desktop machine to provision your device:<BR><BR></FONT><FONT face="Courier New" color=#000080 size=2>rapiconfig /p rpmprov.xml</FONT></P></DIV>
<P>&nbsp;</P>
<P><B><FONT face=Verdana>Launching the Remote Performance Monitor</FONT></B></P>
<P><FONT face=Verdana size=2>To view dynamic performance statistics for your application, launch </FONT><FONT face="Courier New" color=#000080 size=2>netcfrpm.exe</FONT><FONT face=Verdana size=2> from the desktop machine and select the </FONT><FONT face="Courier New" color=#000080 size=2>"Live Counters...."</FONT><FONT face=Verdana size=2> option under the </FONT><FONT face="Courier New" color=#000080 size=2>File</FONT><FONT face=Verdana size=2> menu.&nbsp; Doing so displays the following window:</FONT></P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/124431954/"><IMG height=610 alt=TuneIn1 src="http://static.flickr.com/52/124431954_ae843e7c2a_o.jpg" width=810></A>
<P><FONT face=Verdana size=2>Before you can view live statistics, you must connect the RPM to your device and specify the application you'd like to run.&nbsp; The instructions for connecting the RPM to your device vary based on whether the connection between your desktop machine and your device is via Active Sync or an Ethernet connection.&nbsp; If your connection is over ActiveSync, your device will automatically appear in the </FONT><FONT face="Courier New" color=#000080 size=2>Device</FONT><FONT face=Verdana size=2> drop down in the RPM user interface.&nbsp; If your desktop machine is connected to the device through a direct network connection, you must know the IP address and port number through which the RPM can connect to your device.&nbsp; This information can be obtained by running <FONT color=#000080>netcflauch.exe</FONT> from the <FONT color=#000080>\windows</FONT> directory of your device.&nbsp; Running </FONT><FONT face="Courier New" color=#000080 size=2>netcflaunch.exe</FONT><FONT face=Verdana size=2> displays the following:</FONT></P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/124431953/"><IMG height=367 alt=Launcher src="http://static.flickr.com/52/124431953_9b436bc834_o.jpg" width=250></A>
<P><FONT face=Verdana size=2>Using the data displayed by </FONT><FONT face="Courier New" color=#000080 size=2>netcflaunch.exe</FONT><FONT face=Verdana size=2>, enter the IP address and port number in format </FONT><FONT face="Courier New" color=#000080 size=2>&lt;IPAddress&gt;&lt;single space&gt;&lt;port number&gt;</FONT><FONT face=Verdana size=2> in the </FONT><FONT face="Courier New" color=#000080 size=2>Device</FONT><FONT face=Verdana size=2> drop down in the RPM user interface.</FONT></P>
<P><FONT face=Verdana size=2>Before connecting to the device, you must specify the application you'd like to monitor using the </FONT><FONT face="Courier New" color=#000080 size=2>Application</FONT><FONT face=Verdana size=2> text box.&nbsp; Be sure to type the fully qualified path name to the executable you wish to run on the device.&nbsp; For example, </FONT><FONT face="Courier New" color=#000080 size=2>\Program Files\poomcominterop\poomcominterop.exe</FONT><FONT face=Verdana size=2>.&nbsp; If your applications takes command line parameters, you can specify them in the </FONT><FONT face="Courier New" color=#000080 size=2>Parameters</FONT><FONT face=Verdana size=2> text box.&nbsp; If you need to specify more than one parameter, be sure to separate them with a space.</FONT></P>
<P><FONT face=Verdana size=2>After you've selected the device to connect to, and specified the application to launch, click the </FONT><FONT face="Courier New" color=#000080 size=2>Connect</FONT><FONT face=Verdana size=2> button in the lower right corner of RPM's user interface.&nbsp; The RPM will send a command to the device to remotely launch the application and start pulling back performance statistics.&nbsp; RPM displays the statistics in tabular form as shown in the following picture:</FONT></P>
<P><FONT face=Verdana size=2></FONT>&nbsp;</P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/124431956/"><IMG height=610 alt=TuneIn2 src="http://static.flickr.com/55/124431956_0e2a4e2041_o.jpg" width=812></A>
<P><FONT face=Verdana size=2>Again, a description of the various counters can be found on <A href="/davidklinems/archive/2005/12/09/502125.aspx">David Kline's blog</A>.</FONT></P>
<P><B><FONT face=Verdana>Viewing Performance Statistics using Perfmon</FONT></B></P>
<P><FONT face=Verdana size=2>While viewing performance statistics in RPM is useful, it's often easier to spot performance trends by viewing the data in a graphical form.&nbsp; The RPM enables you to view the statistics graphically by sending all the data it collects to the Windows Performance Monitor.&nbsp; After opening performance monitor, select the "</FONT><FONT face="Courier New" color=#000080 size=2>Add Counter</FONT><FONT face=Verdana size=2>" option.&nbsp; In the dialog that is displayed you'll see counters corresponding to each category of performance statistic gathered by the RPM as show below:</FONT></P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/124431957/"><IMG height=455 alt=TuneIn3 src="http://static.flickr.com/38/124431957_952e9cf1b8_o.jpg" width=654></A>
<P><FONT face=Verdana size=2>After selecting the counters you'd like to view, the values for those counters appear as a line in the Perfmon graph.&nbsp; You may need to adjust the scale Perfmon uses to display a counter depending on the expected range of values.&nbsp; In the picture below I've chosen to view counters representing the size of the GC heap and the total number of bytes allocated while my application runs. </FONT></P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/73548466/"><IMG height=673 alt=GCHeap src="http://static.flickr.com/34/73548466_cb15c52ed7_o.jpg" width=800></A>
<P><B><FONT face=Verdana>Other RPM Features</FONT></B></P>
<P><FONT face=Verdana size=2>In addition to viewing performance statistics, the RPM also allows you to set various configuration options for your device.&nbsp; Selecting the Logging Options item from the Device menu displays the following dialog:</FONT></P><A title="Photo Sharing" href="http://www.flickr.com/photos/stevenjpr/128038407/"><IMG height=357 alt=TuneIn4 src="http://static.flickr.com/56/128038407_d2e829df04_o.jpg" width=464></A>
<P><FONT face=Verdana size=2>As you can see, the RPM allows you to configure the various types of logging done by the Compact Framework and to put your device into a state in which you can attach the debugger to any managed process.&nbsp; The following links provide more information about the various logging options:</FONT></P>
<UL>
<LI><FONT face=Verdana size=2><B>Loader logging:</B> <A href="/stevenpr/archive/2005/02/28/381744.aspx">http://blogs.msdn.com/stevenpr/archive/2005/02/28/381744.aspx</A> </FONT>
<LI><FONT face=Verdana size=2><B>Interop logging:</B> <A href="/stevenpr/archive/2005/06/22/431612.aspx">http://blogs.msdn.com/stevenpr/archive/2005/06/22/431612.aspx</A> </FONT></LI></UL>
<P><FONT face=Verdana size=2>Thanks,</FONT></P>
<P><FONT face=Verdana size=2>Steven</FONT></P>
<P><FONT face=Rockwell size=2>This posting is provided "AS IS" with no warranties, and confers no rights.</FONT></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=577636" width="1" height="1">DiagnosticsBook updates for Customizing the CLRhttp://blogs.msdn.com/b/stevenpr/archive/2006/03/28/book-updates-for-customizing-the-clr.aspxWed, 29 Mar 2006 04:53:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:563599stevenpr0http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=563599http://blogs.msdn.com/b/stevenpr/archive/2006/03/28/book-updates-for-customizing-the-clr.aspx#comments<P><FONT face=Verdana size=2>Releasing a book before the product on which it is based ships is always a risky proposition as product changes are inevitable, which may invalidate some of what you've written.&nbsp; My situation is no exception.&nbsp; I finished writing my <A href="http://www.microsoft.com/MSPress/books/6895.asp" mce_href="http://www.microsoft.com/MSPress/books/6895.asp">book on advanced CLR programming techniques</A> almost a year before version 2.0 of the .Net Framework was released.&nbsp; Over time, various readers have pointed out places where the book is now inaccurate.&nbsp; This post summarizes what's different and provides updated versions of all the book's samples.</FONT></P>
<UL>
<LI><FONT face=Verdana size=2><B>Chapter 7, Page 187.</B> </FONT><FONT face="Courier New" color=#000080 size=2>System.Configuration</FONT><FONT face=Verdana size=2> should be in the list of assemblies the CLR unifies when an application is run.</FONT></LI>
<LI><FONT face=Verdana size=2><B>Chapter 8, 196.</B>&nbsp; The </FONT><FONT face="Courier New" color=#000080 size=2>GetTextualIdentityFromFile</FONT><FONT face=Verdana size=2> and </FONT><FONT face="Courier New" color=#000080 size=2>GetTextualIdentityFromStream</FONT><FONT face=Verdana size=2> methods on </FONT><FONT face="Courier New" color=#000080 size=2>ICLRAssemblyIdentityManager</FONT><FONT face=Verdana size=2> are now called </FONT><FONT face="Courier New" color=#000080 size=2>GetBindingIdentityFromFile</FONT><FONT face=Verdana size=2> and </FONT><FONT face="Courier New" color=#000080 size=2>GetBindingIdentityFromStream</FONT><FONT face=Verdana size=2>.</FONT></LI>
<LI><FONT face=Verdana size=2><B>Chapter 8, 209.</B>&nbsp; I suggest that the managed portion of the Cocoon host (the <I>CocoonHostRuntime</I> assembly) could be included in the cocoon along with the files that constitute the application.&nbsp;&nbsp; While this is true, it's probably more of a hassle than it's worth because of security and evidence.&nbsp; As described in Chapter 10, assemblies loaded from the cocoon are granted no evidence by default.&nbsp; In order for them to run, the sample includes an implementation of </FONT><FONT face="Courier New" color=#000080 size=2>HostSecurityManager</FONT><FONT face=Verdana size=2> that assigns a custom piece of evidence which causes the Application Domain's security policy to grant at least enough permissions to allow the assemblies in the cocoon to execute.&nbsp; The problem is the implementation of </FONT><FONT face="Courier New" color=#000080 size=2>HostSecurityManager</FONT><FONT face=Verdana size=2> that assigns the evidence and evaluates policy is contained in <I>CocoonHostRuntime</I>.&nbsp; As a result, when <I>CocoonHostRuntime</I> is contained in the cocoon, it doesn't get permission to load.&nbsp; Your classic "chicken and egg" problem....&nbsp; You can work around this by modifying the machine's security policy to grant appropriate permissions to <I>CocoonHostRuntime</I>, but this complicates the deployment of your host.</FONT></LI>
<LI><FONT face=Verdana size=2><B>Chapter 14.</B>&nbsp; This chapter describes a set of hosting APIs you can use to integrate the CLR with an existing cooperative scheduling mechanism.&nbsp; SQLServer 2005 is described as a host that has done this type of integration.&nbsp; However, the SQLServer and CLR teams cut the ability to schedule the CLR onto SQL's fibers.&nbsp; The hosting APIs described in the chapter still exist, but SQLServer doesn't use them.</FONT></LI></UL>
<P><FONT face=Verdana size=2>In addition to these content changes, the book's samples could also use an update.&nbsp; The updates can be found <A href="http://www.airjockeys.com/msdn%20blog/booksamples.zip" mce_href="http://www.airjockeys.com/msdn%20blog/booksamples.zip">here</A>.&nbsp; Most of the samples are just rebuilt with the released version of Visual Studio 2005, which was generally straightforward.&nbsp; </FONT></P>
<P><FONT face=Verdana size=2>However, one sample, the <I>AppDomainViewer</I> sample from Chapter 5, has some worthwhile code changes.&nbsp; There was a bug in the sample that caused the UI to not always be updated properly (I missed a case of </FONT><FONT face="Courier New" color=#000080 size=2>Control.Invoke</FONT><FONT face=Verdana size=2>!).&nbsp; Also, there are some cases where the profiling APIs which are used to attach to processes sometimes fail to attach.&nbsp; Thanks to <A href="http://fasterbetter.weblogs.us/archives/035863.html" mce_href="http://fasterbetter.weblogs.us/archives/035863.html">Paul Perry</A>, most of those cases have been identified and some better error handling code now catches these.</FONT></P>
<P><FONT face=Verdana size=2>Thanks,</FONT></P>
<P><FONT face=Verdana size=2>Steven</FONT></P>
<P><FONT face=Rockwell size=2>This posting is provided "AS IS" with no warranties, and confers no rights.</FONT></P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=563599" width="1" height="1">Custominzing the CLR book.Net Compact Framework GC article in .Net Developers Journalhttp://blogs.msdn.com/b/stevenpr/archive/2006/02/08/528138.aspxThu, 09 Feb 2006 04:23:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:528138stevenpr0http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=528138http://blogs.msdn.com/b/stevenpr/archive/2006/02/08/528138.aspx#comments<p><font face=Verdana size=2>I recently wrote an article for .<a href="http://dotnet.sys-con.com/">Net Developers Journal</a> on how operations like boxing and string manipulations can affect the performance of the Compact Framework's garbage collector. Credit for the ideas and samples in the article go to <a HREF="/romanbat/">Roman Batoukov</a>.<br /><br />Check out the <a href="http://dotnet.sys-con.com/general/currentcover.htm">February issue</a>.<br /><br />For more Compact Framework performance information, see the <a HREF="/netcfteam/archive/2005/05/04/414820.aspx">FAQ</a> on our <a HREF="/netcfteam/">team blog</a>.<br /><br />Thanks,<br />Steven</font></p><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=528138" width="1" height="1">GCThe Design of the .Net Compact Framework CLR, Part III: GC Heap Managementhttp://blogs.msdn.com/b/stevenpr/archive/2005/12/14/503818.aspxThu, 15 Dec 2005 02:31:00 GMT91d46819-8472-40ad-a661-2c78acb4018c:503818stevenpr5http://blogs.msdn.com/b/stevenpr/rsscomments.aspx?WeblogPostID=503818http://blogs.msdn.com/b/stevenpr/archive/2005/12/14/503818.aspx#comments<P><FONT face=Verdana size=2>Here's Part III of the series on the design of the .Net Compact Framework CLR.&nbsp; Previous posts in this series provided an overview of how the CLR manages memory and described the basic design tenants of the JIT compilers:</FONT></P>
<P><FONT face=Verdana size=2><a href="http://blogs.msdn.com/stevenpr/archive/2005/12/12/502908.aspx">Part I, Overview and Background</A></FONT></P>
<P><FONT face=Verdana size=2><a href="http://blogs.msdn.com/stevenpr/archive/2005/12/12/502978.aspx">Part II, Jit Compiler Design Considerations</A></FONT></P>
<P><FONT face=Verdana size=2>This post focuses on the design of the garbage collector from the perspective of how the GC heap is managed.</FONT></P>
<P>---------</P>
<P><FONT face=Verdana size=2>Garbage collection is typically the topic that first comes to mind when discussing how memory is managed on the .Net platform. Not surprisingly, the Compact Framework’s garbage collector differs in many respects from its desktop counterpart due to the constraints in which it must run. Like most other subsystems within the Compact Framework CLR, the garbage collector has been designed to free all the memory it can when the amount of memory available on the device is low.</FONT></P>
<P><FONT face=Verdana size=2>At a high level, the GC performs two basic functions: it allocates memory to hold instances of reference types and it collects the instances that are no longer needed.</FONT></P>
<H2><FONT face="Times New Roman">Allocating Reference Types</FONT></H2>
<P><FONT face=Verdana size=2>As described in <a href="http://blogs.msdn.com/stevenpr/archive/2005/12/12/502908.aspx">Part 1</A>, the GC heap lives in the per-application 32 MB virtual address space. As with the JIT heap, the GC heap starts small and grows incrementally as more space is needed. However, there are two important differences in the way the GC heap grows when compared to the JIT heap: the GC heap grows in fixed increments, and it does not grow unbounded.<BR>&nbsp;</FONT></P>
<P><FONT face=Verdana size=2>The growth increment for the GC heap is generally 64K. When a new 64K “segment” is created, allocations occur from that segment until no more room is available, at which point another segment is created. The Compact Framework GC allocates new segments using the standard Win32 API </FONT><FONT face="Lucida Console" size=2>VirtualAlloc</FONT><FONT face=Verdana size=2>. Allocations within a segment are very fast. Performance tests on version 2 of the .Net Compact Framework show that the allocator can create up to 7.5 million instances of a small reference type per second. The allocator is so fast because the algorithm it uses is simple. A pointer is maintained to the “next available location” in the GC heap. To allocate space for a new instance, the allocator simply moves the pointer by the number of bytes needed to hold the object as shown in Figure 4:</FONT></P>
<P><IMG height=188 src="http://static.flickr.com/20/73548464_970f38bce4_o.jpg" width=448></P>
<P><FONT face=Verdana size=2><B>Figure 4</B><BR><I>Allocating a new reference type is simply a matter of adjusting the “next object” pointer.</I></FONT></P>
<P><FONT face=Verdana size=2>While the default growth increment for the GC heap is 64K, the allocator will grow the heap in larger increments to accommodate objects greater than 64K. For example, if a program attempts to create an object that is 70k, the allocator will create a new segment of that size to store the larger object.<BR>&nbsp;</FONT></P>
<P><FONT face=Verdana size=2>The GC heap grows in increments as described until it reaches 1 MB, at which point a collection begins (more on this later). The GC heap may continue to grow after that, but a collection occurs whenever 1MB of objects has been allocated since the last collection occurred.</FONT></P>
<H2>Collecting Reference Types</H2>
<P><FONT face=Verdana size=2>Now that we’ve seen how the GC heap grows, let’s take a look at how it shrinks. Again, the ability to reduce the size of the GC heap under memory pressure is key to helping applications run well on memory constrained devices. In this section, we’ll look at what causes a collection to occur and when memory is freed and returned to the operating system.<BR>&nbsp;</FONT></P>
<P><FONT face=Verdana size=2>There are several triggers that can cause a garbage collection to occur. As described, one of those triggers is the allocation of 1MB of managed objects. Other triggers include resource failures such as the inability to allocate more memory, create more window handles and so on. See <a href="http://blogs.msdn.com/stevenpr/archive/2004/07/26/197254.aspx">An Overview of the .Net Compact Framework Garbage Collector</A> for more details on what triggers a collection.<BR>&nbsp;</FONT></P>
<P class=MsoNormal><FONT face=Verdana size=2>Memory is not freed and returned to the operating system every time a GC occurs.&nbsp; To understand when memory is freed from the operating system’s perspective, let’s take a closer look at what happens when the collector runs.</FONT></P>
<H3>Unreferenced Objects</H3>
<P><FONT face=Verdana size=2>During every collection, the GC looks through the heap to find objects that are no longer referenced. The memory for these unneeded objects is freed in the sense that more space is now available in the GC heap. After freeing the unreferenced types, it’s possible that some number of 64K segments may be completely empty. If a segment is completely empty, and the GC still has 1MB of allocated segments, the empty 64K segments will be returned to the operating system by calling </FONT><FONT face="Lucida Console" size=2>VirtualFree</FONT><FONT face=Verdana size=2>. With the exception of a “full” GC (described below), the collector always keeps a 1MB cache of 64K segments, even if some of them are empty. By caching segments in this way, performance is improved by reducing the number of calls to </FONT><FONT face="Lucida Console" size=2>VirtualAlloc</FONT><FONT face=Verdana size=2> and </FONT><FONT face="Lucida Console" size=2>VirtualFree</FONT><FONT face=Verdana size=2>.</FONT></P>
<H3><FONT face="Times New Roman">Compacting the GC Heap</FONT></H3>
<P class=MsoNormal><FONT face=Verdana size=2>The GC may optionally compact the heap during a collection.&nbsp; When the heap reaches a state where it is sufficiently fragmented, the collector “compacts” the heap by moving all live objects close to each other.&nbsp; The primary goal in compacting the heap is to make larger blocks of memory available in which to allocate more objects.&nbsp; Figure 5 represents the contents of a GC heap before and after compaction.</FONT></P>
<P><IMG height=375 src="http://static.flickr.com/20/73548465_5ff931caa1_o.jpg" width=718></P>
<P class=MsoNormal><FONT face=Verdana size=2><B>Figure 5</B><BR><I>The contents of a sample GC heap before and after compaction</I></FONT></P>
<P class=NormalContinuation><FONT face=Verdana size=2>As with the “simple” object collection, the GC will return empty 64K segments to the operating system as long as the 1MB segment cache is full.</FONT></P>
<H3>A "Full" GC</H3>
<P class=MsoNormal><FONT face=Verdana size=2>Under the normal course of events, the GC works as described above: periodic collections are made after every 1MB of allocations, the heap is compacted if it gets too fragmented, and empty segments are returned to the operating system as long as the collector’s 1 MB cache is full.</FONT></P>
<P><FONT face=Verdana size=2>There three scenarios, however, in which more drastic steps are taken to make more memory available. These scenarios align exactly with the times at which the JIT reduces the size of it’s heap as described in <a href="http://blogs.msdn.com/stevenpr/archive/2005/12/12/502978.aspx">Part II</A>: when a failure to allocate memory or other resource occurs, when an application is moved to the background, or when an application receives the </FONT><FONT face="Lucida Console" size=2>WM_HIBERNATE</FONT><FONT face=Verdana size=2> message from the operating system. At these times, the GC will hot hold onto its 1MB segment cache. It will collect all unreferenced objects, compact the heap, and free any memory it can.</FONT></P>
<H3>Pulling it All Together</H3>
<P><FONT face=Verdana size=2>Now that we’ve seen how the GC allocates and frees memory, let’s look at the size of the GC heap over the lifetime of an application.</FONT></P>
<P><IMG height=673 src="http://static.flickr.com/34/73548466_cb15c52ed7_o.jpg" width=800></P>
<P class=FigNum><B><FONT face=Verdana size=2>Figure 6</FONT></B></P>
<P class=FigNum><I><FONT face=Verdana size=2>The size of the GC heap over the lifetime of an application.</FONT></I></P>
<P class=MsoCaption><FONT face=Verdana size=2>The graph in Figure 6 tracks two pieces of data. The yellow line shows the cumulative number of bytes the garbage collector has been asked to allocate over the lifetime of the application. This number will continue to grow without bounds as long as the application continues to allocate new objects.<BR>&nbsp;</FONT></P>
<P class=MsoCaption><FONT face=Verdana size=2>The blue line in Figure 6 shows the size of the GC heap over time. There are several points worth noting. First, when the application starts and continues to run, we see the size of the GC heap growing in a consistent stair-step fashion. Each “step” in the graph corresponds to a newly created 64K GC segment. Second, we can see that the blue line levels off after some time. As you’d expect from the earlier description of the allocation and collection algorithms, the point at which the size of the heap flattens out is at 1MB. Next, you can see a dramatic drop in the size of the heap. In this case, the drop occurs when I moved the application I was monitoring into the background. After the application switches to the foreground, we start to see the heap growing in 64K chunks again.<BR>&nbsp;</FONT></P>
<P class=MsoCaption><FONT face=Verdana size=2>This series of posts has now covered the basics of how the .Net Compact Framework managed memory, and the design decisions made while building the JIT compilers and the garbage collector. In my next post, I’ll look at how the need to run efficiently on memory constrained devices has affected the design of the CLR’s class loader.</FONT></P>
<P><FONT face=Rockwell size=2>This posting is provided "AS IS" with no warranties, and confers no rights.</FONT></P>
<P class=MsoCaption>&nbsp;</P>
<P><BR>&nbsp;</P><div style="clear:both;"></div><img src="http://blogs.msdn.com/aggbug.aspx?PostID=503818" width="1" height="1">GC