<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Jon Cole's WebLog : Debugging</title><link>http://blogs.msdn.com/joncole/archive/tags/Debugging/default.aspx</link><description>Tags: Debugging</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Creating a Process Memory Dump</title><link>http://blogs.msdn.com/joncole/archive/2007/03/29/creating-a-process-memory-dump.aspx</link><pubDate>Fri, 30 Mar 2007 07:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1992434</guid><dc:creator>joncole</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/joncole/comments/1992434.aspx</comments><wfw:commentRss>http://blogs.msdn.com/joncole/commentrss.aspx?PostID=1992434</wfw:commentRss><description>&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;When trying to help customers debug some issues it is periodically necessary to get a memory dump (snapshot) of a process for analysis at another time or place.&amp;nbsp; This is frequently the case when an error is intermittent or a live debug session is not feasible (like in a production environment).&amp;nbsp; I will discuss the steps necessary to install the right debuggers, attach to the process in question, looking for the right event to occur (knowing when to save the dump) and saving a dump to disk.&amp;nbsp; In this case I will be looking at BtsNtSvc.exe, which is the BizTalk NT Service process. 
&lt;H2&gt;&lt;STRONG&gt;&lt;U&gt;Installing the Debuggers&lt;/U&gt;&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;Many debuggers have support for creating (or opening) memory dumps, including Visual Studio 2005.&amp;nbsp; However, because of the size of Visual Studio and license requirements, I will discuss the use of the freely downloadable debugging tools that Microsoft provides - &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx" mce_href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx"&gt;Debugging Tools for Windows&lt;/A&gt;.&amp;nbsp; Make sure you install the correct version for you processor architecture (x86 vs x64). 
&lt;P&gt;You may want to read the &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx" mce_href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx"&gt;Getting Started &lt;/A&gt;page for supplemental information.&amp;nbsp; These tools come with several debuggers, most of which support the same types of operations.&amp;nbsp; Windbg.exe is the GUI version, but you can also use cdb.exe (a command line based debugger) and accomplish pretty much the same things because they are built on top of the same underlying debugging libraries.&amp;nbsp; In this article I will focus on WinDbg.&amp;nbsp; 
&lt;H2&gt;&lt;STRONG&gt;&lt;U&gt;Setting your Symbol Path&lt;/U&gt;&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;The symbol path (path to pdb files) can be set in several ways.&amp;nbsp; You can set it before you start the debugger by using the _NT_SYMBOL_PATH environment variable or at runtime.&amp;nbsp; To set the symbol path at runtime, select &lt;EM&gt;File-&amp;gt;Symbol File Path&lt;/EM&gt;.&amp;nbsp; This symbol path is basically just a semicolon (;) delimited list of search paths that the debugger should use when trying to locate debug symbols for the exe/dlls in your process.&amp;nbsp; I will try to write more about setting up your symbol path at a later date.&amp;nbsp; 
&lt;P&gt;You can also set the symbol path by using the .&lt;FONT color=#0080ff&gt;sympath &lt;/FONT&gt;command (more information below on how to run commands).&amp;nbsp; See the debugger help files for more information. 
&lt;P&gt;Check out &lt;A class="" href="http://support.microsoft.com/kb/311503" target=_blank mce_href="http://support.microsoft.com/kb/311503"&gt;KB article 311503&lt;/A&gt; for more information on setting symbols, including how to get publicly available symbols for microsoft products.&amp;nbsp;&amp;nbsp;It aslo includes a&amp;nbsp;video tuturial on how to set the symbol path in the Visual Studio.Net debugger. 
&lt;H2&gt;&lt;STRONG&gt;&lt;U&gt;Attaching to the process&lt;/U&gt;&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;You can attach to the process in a couple of ways.&amp;nbsp; Choose one of the following: 
&lt;OL&gt;
&lt;LI&gt;&amp;nbsp;From the command line you can type any of the following: 
&lt;OL&gt;
&lt;LI&gt;"Windbg.exe -p &amp;lt;processID&amp;gt;"&amp;nbsp; (example: "windbg.exe -p 1234") 
&lt;LI&gt;"windbg.exe -pn &amp;lt;processName&amp;gt;"&amp;nbsp; (example: "windbg.exe -pn btsntsvc.exe") 
&lt;LI&gt;Note that you can add "-g" (lower case g) to any of the above to avoid breaking into the debugger immediately after attaching.&lt;/LI&gt;&lt;/OL&gt;
&lt;LI&gt;After starting WinDbg: &lt;/LI&gt;
&lt;OL&gt;
&lt;LI&gt;Select &lt;EM&gt;File-&amp;gt;Attach to a Process&lt;/EM&gt; from the menu 
&lt;LI&gt;Select the Process from the list in the new windows that comes up &lt;A href="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_AttachToProcess%5B24%5D.jpg" mce_href="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_AttachToProcess%5B24%5D.jpg" atomicselection="true"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=521 src="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_AttachToProcess_thumb%5B16%5D.jpg" width=381 border=0 mce_src="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_AttachToProcess_thumb%5B16%5D.jpg"&gt;&lt;/A&gt;&amp;nbsp;&lt;/LI&gt;&lt;/OL&gt;&lt;/OL&gt;
&lt;P&gt;Once you have the debugger open, you can either type ".hh" in the command box or by selecting &lt;EM&gt;Help-&amp;gt; Contents &lt;/EM&gt;from the menu.&amp;nbsp; Note that you will have to break into the debugger before you can run any commands in the command box.&amp;nbsp; Hit "Ctrl-Break" on your keyboard or click the pause button on the toolbar to break into the debugger.&lt;/P&gt;
&lt;P&gt;FYI, here is a snapshot of the command box (found in the lower left hand corner of the window).&amp;nbsp; I have circled it in red.&amp;nbsp;&amp;nbsp; Note that the&amp;nbsp; "0 : 003" indicates that I am currently examining thread number 3.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_Command_Box%5B3%5D.jpg" mce_href="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_Command_Box%5B3%5D.jpg" atomicselection="true"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=141 src="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_Command_Box_thumb%5B1%5D.jpg" width=240 border=0 mce_src="http://blogs.msdn.com/blogfiles/joncole/WindowsLiveWriter/CreatingaProcessMemoryDump_11DED/Windbg_Command_Box_thumb%5B1%5D.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;&lt;U&gt;Looking for the right event&lt;/U&gt;&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;There may be several types of events you are interested in and several ways to locate the event you are interested in.&amp;nbsp;&amp;nbsp;I will only speak of three types of events in this article.&amp;nbsp; Some will result in the debugger breaking for you automatically, others you will have to tell the debugger you are interested in stopping if it occurs. I will primarily&amp;nbsp;focus on .NET exceptions in this article.&amp;nbsp;&amp;nbsp; 
&lt;OL&gt;
&lt;LI&gt;Access Violation (a.k.a. AV).&amp;nbsp; This type of error will result in the process breaking into the debugger without any special setup on your part.&amp;nbsp; AVs occur when your program tries to access memory that it doesn't have permission to access.&amp;nbsp; Examples would be&amp;nbsp;reading/writing protected memory or&amp;nbsp;trying to use&amp;nbsp;an object that is null.&amp;nbsp; In .NET, these will result in either an AccessViolationException (read/write protected memory) or NullReferenceException (null object referenced in code).&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;.NET exception at the time it is thrown (a.k.a first chance exception).&amp;nbsp; Windbg will not break into the debugger for this one automatically.&amp;nbsp; You have to tell it that you want it to stop.&amp;nbsp; You can do this by running the command &lt;STRONG&gt;&lt;EM&gt;&lt;FONT color=#0080ff&gt;sxe clr&lt;/FONT&gt;&lt;/EM&gt;&lt;/STRONG&gt;.&amp;nbsp; If you need to stop breaking into the debugger every time a .NET exception is thrown, you can use the &lt;STRONG&gt;&lt;EM&gt;&lt;FONT color=#0080ff&gt;sxi clr&lt;/FONT&gt;&lt;/EM&gt;&lt;/STRONG&gt; command.&amp;nbsp; Keep in mind that just because an exception is thrown does not mean that it is unexpected and unhandled.&amp;nbsp; The process may expect to get exceptions in certain recoverable situations and the user may be completely unaware that anything has happened.&lt;/LI&gt;
&lt;LI&gt;.NET exception is thrown and is not handled.&amp;nbsp; This will result in your process crashing.&amp;nbsp; This is especially true in .NET 2.0 and later.&amp;nbsp; In earlier versions of the framework, an exception being thrown and unhandled on a thread pool thread did not necessarily cause the application to shut down - it was swallowed.&amp;nbsp; This made debugging applications more difficult, so in V2.0 of the framework an unhandled exception causes the application to shutdown immediately to make the system&amp;nbsp;easier to&amp;nbsp;debug.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Now that we know how to get the system to break into the debugger, we need to be able to look at the exception that occurred to determine if it is the one we care about.&amp;nbsp; I will discuss how to do this in V2.0 of the framework.&amp;nbsp; It can be done in earlier versions of the framework also, but it isn't quite as easy.&lt;/P&gt;
&lt;P&gt;Because Windbg is primarily a native application debugging tool, you have to load what is called a debugger extension to enable you to debug managed code.&amp;nbsp; This extension is called sos.dll and it sits in the .net v2.0 installation dir (same dir as mscorwks.dll).&amp;nbsp; You can use the following command to easily load it&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp; &lt;EM&gt;&lt;STRONG&gt;&lt;FONT color=#0080ff&gt;.loadby sos mscorwks&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;This tells windbg to look in the same directory as mscorwks.dll (always loaded into .NET applications) to find sos.dll.&amp;nbsp; Command that are loaded from a debugger extension dll are always prefixed with an exclamation mark (!).&lt;/P&gt;
&lt;P&gt;When you have sos.dll loaded you can run &lt;FONT color=#0080ff&gt;!help.&lt;/FONT&gt;&lt;FONT color=#000000&gt;&amp;nbsp; Note that if you have multiple extensions loaded, you may have to prefix your commands with the specific extension that has the command you want.&amp;nbsp; For example: &lt;FONT color=#0080ff&gt;!sos.help&lt;/FONT&gt;.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Now, when the debugger breaks, we can do run two commands to help us figure out where we are and what type of exception occured. &lt;FONT color=#0080ff&gt;!sos.printexception&lt;/FONT&gt; (or &lt;FONT color=#0080ff&gt;!pe&lt;/FONT&gt; is the shorthand version) and &lt;/FONT&gt;&lt;FONT color=#0080ff&gt;!clrstack&lt;/FONT&gt;&lt;FONT color=#000000&gt;.&amp;nbsp; If the exception type, message and stack trace match the one you see in logs, event viewer, etc., then you have (hopefully) found the right exception.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Here is some sample output when a first chance .NET exception occurs:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;(650.1c9c): &lt;STRONG&gt;CLR exception&lt;/STRONG&gt; - code e0434f4d (first chance)&lt;BR&gt;First chance exceptions are reported before any exception handling.&lt;BR&gt;This exception may be expected and handled.&lt;BR&gt;eax=0012f298 ebx=00181a60 ecx=00000000 edx=00000025 esi=0012f324 edi=e0434f4d&lt;BR&gt;eip=77e55e02 esp=0012f294 ebp=0012f2e8 iopl=0 nv up ei pl nz na po nc&lt;BR&gt;cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202&lt;BR&gt;KERNEL32!RaiseException+0x53:&lt;BR&gt;77e55e02 5e pop esi&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;0:000&amp;gt; &lt;FONT color=#0080ff&gt;!pe&lt;BR&gt;&lt;/FONT&gt;Exception object: 01355858&lt;BR&gt;Exception type: &lt;STRONG&gt;System.InvalidOperationException&lt;/STRONG&gt;&lt;BR&gt;Message: &lt;STRONG&gt;This is a sample exception message for an InvalidOperationException&lt;/STRONG&gt;&lt;BR&gt;InnerException: &amp;lt;none&amp;gt;&lt;BR&gt;StackTrace (generated):&lt;BR&gt;&amp;lt;none&amp;gt;&lt;BR&gt;StackTraceString: &amp;lt;none&amp;gt;&lt;BR&gt;HResult: 80131509&lt;BR&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;0:000&amp;gt;&lt;FONT color=#0080ff&gt; !clrstack&lt;BR&gt;&lt;/FONT&gt;OS Thread Id: 0x1c9c (0)&lt;BR&gt;ESP EIP &lt;BR&gt;0012f370 77e55e02 [HelperMethodFrame: 0012f370] &lt;BR&gt;0012f414 00d8021e &lt;STRONG&gt;Test.AnotherFunctionThatThrowsAnException(System.String)&lt;BR&gt;&lt;/STRONG&gt;0012f420 00d801c2 &lt;STRONG&gt;Test.SomeFunction()&lt;BR&gt;&lt;/STRONG&gt;0012f428 00d800b2 &lt;STRONG&gt;Test.Main()&lt;BR&gt;&lt;/STRONG&gt;0012f69c 79e88f63 [GCFrame: 0012f69c] &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If the exception you are currently looking at is not the one you were looking for, then you can tell the debugger to let the process continue until the next event by using the &lt;FONT color=#0080ff&gt;g &lt;/FONT&gt;command (go).&amp;nbsp; Of course, these debuggers support break points also, but that is a discussion for another day.&lt;FONT color=#0080ff&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;H2&gt;&lt;STRONG&gt;&lt;U&gt;Saving the Dump File&lt;/U&gt;&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;Now that you have the process broken into the debugger at the right place, you can use &lt;FONT color=#0080ff&gt;.dump&lt;/FONT&gt; command to write the memory dump out to a file.&amp;nbsp; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT color=#0080ff&gt;.dump &amp;lt;options&amp;gt; &amp;lt;path to file&amp;gt;&lt;/FONT&gt; 
&lt;P&gt;example: &lt;FONT color=#0080ff&gt;.dump /mfh c:\temp\myDump.dmp&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT color=#0080ff&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I would recommend the /mfh options for this command&amp;nbsp;as I show above.&amp;nbsp; You can read the help files for the &lt;FONT color=#0080ff&gt;.dump&lt;/FONT&gt; command to get more information on the options you can use and what they imply.&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;&lt;U&gt;Just a reminder...&lt;/U&gt;&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;One last warning about memory dumps before we are done.&amp;nbsp; Memory dumps contain the memory snapshot of the process.&amp;nbsp; This memory can contain private information that you and/or your customers wouldn't want to give out to just anyone.&amp;nbsp; Some examples:&amp;nbsp; usernames and passwords, credit card numbers, etc - anything that is in memory at the time the dump is taken.&amp;nbsp;&amp;nbsp;Consider yourself warned - don't give a copy of the memory dump to just anyone.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1992434" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/joncole/archive/tags/Debugging/default.aspx">Debugging</category></item><item><title>Debugging a memory leak in managed code: Ping - SendAsync</title><link>http://blogs.msdn.com/joncole/archive/2005/12/15/Debugging-a-memory-leak-in-managed-code_3A00_-Ping-_2D00_-SendAsync.aspx</link><pubDate>Fri, 16 Dec 2005 02:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:505627</guid><dc:creator>joncole</dc:creator><slash:comments>19</slash:comments><comments>http://blogs.msdn.com/joncole/comments/505627.aspx</comments><wfw:commentRss>http://blogs.msdn.com/joncole/commentrss.aspx?PostID=505627</wfw:commentRss><description>&lt;P&gt;Included in&amp;nbsp;version 2.0 of the .NET framework is a Ping class (System.Net.NetworkInformation namespace) that can be used to monitor the up/down status of a network connection to a server.&amp;nbsp; We recently realized that we had a minor bug in the class that can present itself as a major problem - a memory leak.&amp;nbsp; Fortunately there is an easy &lt;A href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;amp;sectionid=4037&amp;amp;postid=505627#workaround" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;amp;sectionid=4037&amp;amp;postid=505627#workaround"&gt;workaround&lt;/A&gt; to this problem.&amp;nbsp;I thought I would take this as an oportunity to demonstrate how to&amp;nbsp;use the&amp;nbsp;windbg debugger&amp;nbsp;as I explain how&amp;nbsp;we figured out what was&amp;nbsp;going wrong.&lt;/P&gt;
&lt;P&gt;Lets consider this simple console ping application that sends&amp;nbsp;a series of&amp;nbsp;ping requests to a server using the SendAsync method.&lt;/P&gt;
&lt;TABLE class="" borderColor=gray cellSpacing=0 cellPadding=4 bgColor=silver border=2&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;using System;&lt;BR&gt;using System.Threading;&lt;BR&gt;using System.Net.NetworkInformation;&lt;/FONT&gt;&lt;/P&gt;&lt;FONT color=#0000ff&gt;
&lt;P&gt;&lt;BR&gt;class program {&lt;BR&gt;&amp;nbsp;static int PingsOutstanding;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;static void Main(string[] args)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;string targetServer = "&lt;A href="http://www.contoso.com/" mce_href="http://www.contoso.com"&gt;www.contoso.com&lt;/A&gt;";&lt;BR&gt;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; 1000; i++) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;PingServer(targetServer);&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;int currentcount = PingsOutstanding;&lt;BR&gt;&amp;nbsp;&amp;nbsp;while (currentcount &amp;gt; 0) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine("waiting for {0} ping requests to complete", currentcount);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.Sleep(1000);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;currentcount = PingsOutstanding;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;//the calls to the GC are just for debugging purposes&lt;BR&gt;&amp;nbsp;&amp;nbsp;Console.WriteLine("Calling GC.Collect()");&lt;BR&gt;&amp;nbsp;&amp;nbsp;GC.Collect();&lt;BR&gt;&amp;nbsp;&amp;nbsp;GC.WaitForPendingFinalizers();&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;Console.WriteLine("Press &amp;lt;enter&amp;gt; to exit application");&lt;BR&gt;&amp;nbsp;&amp;nbsp;Console.ReadLine();&lt;BR&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;static void PingServer(string hostnameoraddress)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;try {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Ping pingsender = new Ping();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;pingsender.PingCompleted += new PingCompletedEventHandler(OnPingCompleted);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;pingsender.SendAsync(hostnameoraddress, null);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Interlocked.Increment(ref PingsOutstanding);&lt;BR&gt;&amp;nbsp;&amp;nbsp;} catch (Exception ex) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(ex);&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp;static void OnPingCompleted(object sender, PingCompletedEventArgs e)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;Interlocked.Decrement(ref PingsOutstanding);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;try {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Ping pingsender = (Ping)sender;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;pingsender.Dispose();&lt;BR&gt;&amp;nbsp;&amp;nbsp;} catch (Exception ex) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(ex);&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;This application will not consume a ton of memory under normal operation but if you increase the number of ping requests that are sent, you will see that memory consumption also climbs.&amp;nbsp; Given that the .Net framework uses a garbage collection approach to memory allocation and cleanup, you would expect that the memory would be cleaned up properly within a reasonable amount of time.&amp;nbsp; You should also notice that I am calling pingSender.Dispose() which we would hope would release the resources being held by this object.&lt;/P&gt;
&lt;P&gt;For demonstration purposes I have added a Console.ReadLine() call at the end of the application so that it won't exit.&amp;nbsp; I have&amp;nbsp;also added a call to GC.Collect() and GC.WaitForPendingFinalizers() to make sure that when I go to debug this I am certain that the GC has recently run and cleaned up any objects that are available for cleanup.&amp;nbsp; It is not usually advisable to force GC collections except for debugging purposes.&amp;nbsp; See &lt;A href="http://blogs.msdn.com/maoni/" mce_href="http://blogs.msdn.com/maoni/"&gt;Maoni's blog &lt;/A&gt;for great information on how the GC works and how to use it effectively.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;U&gt;Using Windbg.exe&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;I chose to use Windbg because I have found it to be the best debugger for memory leaks.&amp;nbsp; It is a very powerful GUI debugger that is used very frequently inside of Microsoft for debugging everything from application bugs to OS bugs.&amp;nbsp; You can download it from here: &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx" mce_href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx"&gt;http://www.microsoft.com/whdc/devtools/debugging/default.mspx&lt;/A&gt;.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;A couple of quick notes before I begin:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;updates to&amp;nbsp;these debugging tools are available regularly, so make sure to update periodically. 
&lt;LI&gt;I will color commands that are to be run inside the debugger in &lt;FONT color=#008000&gt;green&lt;/FONT&gt;.&amp;nbsp; 
&lt;LI&gt;I have access to all of the debugger symbols for the .Net framework, but you don't.&amp;nbsp; However, most of the information you need should be accessible by using ".symfix" as noted below.&amp;nbsp; The principles discussed here apply to debugging a memory leak in any managed application. 
&lt;UL&gt;
&lt;LI&gt;public microsoft symbols can loaded into windbg using the &lt;FONT color=#008000&gt;.symfix&lt;/FONT&gt;&amp;nbsp; followed by a &lt;FONT color=#008000&gt;.reload&lt;/FONT&gt; command (requires internet connection to a microsoft http server)&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;I may trim sample output (&lt;FONT color=#800080&gt;colored in purple&lt;/FONT&gt;) from the debugger&amp;nbsp;in order to focus on the important information.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Now, Windbg is a native windows debugger and doesn't really know much about the .Net framework, so you have to load an extension to the debugger that understands managed applications.&amp;nbsp; SOS.dll is the debugger extension we are looking for. In the command window this will load the sos extension:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT color=#008000&gt;.loadby sos mscorwks&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This command tells the debugger to load the sos dll by looking in the same directory as the mscorwks dll, which is a core dll that is always loaded in a managed application.&amp;nbsp;&amp;nbsp;Note that Windbg breaks into the debugger immediately upon loading the application, so mscorwks will not be loaded at this point.&amp;nbsp; You will have to run the application long enough for the .NET framework code to be loaded.&amp;nbsp; You can actually tell the debugger to break when mscorwks is loaded by running this in the command window:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT color=#008000&gt;sxe ld:mscorwks&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;There are two ways that&amp;nbsp;you can run commands from the sos this extension dll:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT color=#008000&gt;!&amp;lt;command&amp;gt; or !sos.&amp;lt;command&amp;gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Here are examples for the help function found in sos&amp;nbsp;(it prints usage information):&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT color=#008000&gt;!help&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!sos.help&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The second one is useful when you have multiple extensions that share common function names.&lt;/P&gt;
&lt;P&gt;When debugging this leak, I actually let the app run until it blocked on the call to Console.ReadLine() so that GC should have cleaned up.&amp;nbsp; The first thing I do when dealing with a managed memory leak is to look at all the objects that have been created by the runtime and see if I see any that jump out at me.&amp;nbsp; Lets look at the heap and see what it contains.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!dumpheap -stat&lt;/FONT&gt;&lt;FONT color=#008000&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#800080&gt;total 20600 objects&lt;BR&gt;Statistics:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp; Count&amp;nbsp;&amp;nbsp;&amp;nbsp; TotalSize Class Name&lt;BR&gt;7a76eb14&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Net.DnsPermission&lt;BR&gt;7a755834&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Diagnostics.PerformanceCounterCategoryType&lt;BR&gt;7a753394&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Diagnostics.TraceOptions&lt;BR&gt;7a71a710&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Net.TimeoutValidator&lt;BR&gt;7912b908&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Collections.Generic.GenericEqualityComparer`1[[System.String, mscorlib]]&lt;BR&gt;79112c90&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Collections.Comparer&lt;BR&gt;7910db30&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Threading.SynchronizationContext&lt;BR&gt;7910a718&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.DefaultBinder&lt;BR&gt;79107f40&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.RuntimeTypeHandle&lt;BR&gt;79107ac4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Reflection.__Filters&lt;BR&gt;79102f48&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.__Filters&lt;BR&gt;79102ef8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Reflection.Missing&lt;BR&gt;79101ca8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.RuntimeType+TypeCacheQueue&lt;BR&gt;79100800&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12 System.Text.DecoderExceptionFallback&lt;BR&gt;...(output trimmed)&lt;BR&gt;0105a514&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 77&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4004 System.Configuration.FactoryRecord&lt;BR&gt;791242ec&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 47&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8136 System.Collections.Hashtable+bucket[]&lt;BR&gt;79160a3c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 16000 System.Threading.RegisteredWaitHandle&lt;BR&gt;79124228&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 58&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 19216 System.Object[]&lt;BR&gt;7a779154&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 20000 System.Net.SafeLocalFree&lt;BR&gt;7a778ec0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 20000 System.Net.SafeCloseHandle&lt;BR&gt;7a761bb0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 20000 System.ComponentModel.AsyncOperation&lt;BR&gt;79160b84&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 20000 System.Threading._ThreadPoolWaitOrTimerCallback&lt;BR&gt;7910cf3c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1001&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 20020 Microsoft.Win32.SafeHandles.SafeWaitHandle&lt;BR&gt;791609c8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 24000 System.Threading.RegisteredWaitHandleSafe&lt;BR&gt;79115d0c&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 24000 System.Threading.ManualResetEvent&lt;BR&gt;7a7811f4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 32000 System.Net.NetworkInformation.PingCompletedEventHandler&lt;BR&gt;79160aa8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 32000 System.Threading.WaitOrTimerCallback&lt;BR&gt;7915ff38&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 32000 System.Threading.SendOrPostCallback&lt;BR&gt;7910d2f4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1001&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 36036 System.Threading.ExecutionContext&lt;BR&gt;79124418&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1004&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 44820 System.Byte[]&lt;BR&gt;7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88000 System.Net.NetworkInformation.Ping&lt;BR&gt;00150c90&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 421&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 108132&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Free&lt;BR&gt;790fa3e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5262&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 304552 System.String&lt;BR&gt;Total 20600 objects&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Looking at the columns in the output, MT stands for Method Table and is basically a pointer to the table that describes that type of object.&amp;nbsp; Count is the number of objects that exist in the heap of the given type.&amp;nbsp; TotalSize is the amount of memory that is being consumed by any one type of object.&amp;nbsp; The last column is obviously the fully typed name of the object.&lt;/P&gt;
&lt;P&gt;The first thing that jumps out at me in this case is the fact that we still have a large number of ping objects in the heap even though we aren't holding onto any references in our code.&amp;nbsp; We also called dispose on these objects, so this is a huge red light telling me that something went wrong.&amp;nbsp; Also, the fact that we sent&amp;nbsp;exacly 1000 ping requests and there are exactly 1000 ping objects still hanging around calls my attention.&amp;nbsp; Lets take a look at these ping objects and see why they aren't getting cleaned up (Below I show two ways of doing this, you really only need to do one of them).&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!dumpheap -type Ping&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This does a substring match on any object with Ping in it.&amp;nbsp; In this case it will list both &lt;FONT color=#000000&gt;System.Net.NetworkInformation.Ping objects and&amp;nbsp;System.Net.NetworkInformation.PingCompletedEventHandler objects.&amp;nbsp; I really wanted just the Ping objects, so we could have run this command (using the MT for the ping object - obtained above) &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!dumpheap -mt&lt;/FONT&gt;&lt;FONT color=#800080&gt; &lt;FONT color=#008000&gt;7a7812e0&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;FONT color=#800080&gt;Address&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Size&lt;BR&gt;01271ff0 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012720f8 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012721d0 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012722a8 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;01272380 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;01272458 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;01272530 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;01272608 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012726e0 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012727b8 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;01272890 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;01272968 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;...(output trimmed)&amp;nbsp; &lt;BR&gt;012fada0 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012faeec 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb038 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb184 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb2d0 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb41c 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb568 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb6b4 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb800 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fb94c 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fba98 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fbbe4 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fbd30 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;012fbe7c 7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;total 1000 objects&lt;BR&gt;Statistics:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MT&amp;nbsp;&amp;nbsp;&amp;nbsp; Count&amp;nbsp;&amp;nbsp;&amp;nbsp; TotalSize Class Name&lt;BR&gt;7a7812e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 88000 System.Net.NetworkInformation.Ping&lt;BR&gt;Total 1000 objects&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#800080&gt;&amp;nbsp;&lt;/FONT&gt;Notice that the MT for all of the above objects matches that for the ping object.&amp;nbsp; The left hand column is the memory address where the object resides.&amp;nbsp; We can use this address to examine the actual ping object.&amp;nbsp; To take a look at the first object in the above list we would use this command:&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!dumpobject &lt;/FONT&gt;&lt;FONT color=#008000&gt;01271ff0 &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;I am not going to go into details at this point because this won't lead us where the problem lies.&amp;nbsp; I thought I would list the dumpobject command just to point it out to you.&amp;nbsp; The problem in this case is that objects that we think should be cleaned up are not cleaned up as expected.&amp;nbsp; This means that there must be a reference to the object somewhere.&amp;nbsp; The following command will help you to see what objects hold references to an object in question.&amp;nbsp; We will use the same object address&amp;nbsp;we used in the dumpobject example:&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!gcroot &lt;/FONT&gt;&lt;FONT color=#008000&gt;01271ff0 &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#800080&gt;Note: Roots found on stacks may be false positives. Run "!help gcroot" for&lt;BR&gt;more info.&lt;BR&gt;Scan Thread 0 OSTHread 2f8&lt;BR&gt;Scan Thread 2 OSTHread fcc&lt;BR&gt;Scan Thread 3 OSTHread de8&lt;BR&gt;Scan Thread 4 OSTHread eb8&lt;BR&gt;Scan Thread 8 OSTHread c8c&lt;BR&gt;Scan Thread 12 OSTHread 464&lt;BR&gt;Scan Thread 13 OSTHread 1e0&lt;BR&gt;DOMAIN(0014BF60):HANDLE(Strong):8f15b8:Root:0128d2c0(System.Threading._ThreadPoolWaitOrTimerCallback)-&amp;gt;&lt;BR&gt;01271ff0(System.Net.NetworkInformation.Ping)&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#800080&gt;&lt;FONT color=#000000&gt;This tool scans the threads to find any object that holds a reference to the given memory address.&amp;nbsp; We can see that some threadpool object is holding onto us.&amp;nbsp; If we go back to the objects on the heap we can see that there are these _ThreadPoolWaitOrTimerCallback objects on the heap also.&amp;nbsp; Now, I don't know a ton about the thread pool, but I would not expect those callback objects to still be on the heap either because they are most likely specific to a single usage of a threadpool thread.&amp;nbsp;We could dump all of the _ThreadPoolWaitOrTimerCallback objects and check their roots (the objects holding onto them), but why dump the more objects from the heap?&amp;nbsp; The output from !gcroot gave us a pointer to an instance that we can quickly examine.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;!&lt;/FONT&gt;&lt;FONT color=#008000&gt;gcroot 0128d2c0&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#800080&gt;Note: Roots found on stacks may be false positives. Run "!help gcroot" for&lt;BR&gt;more info.&lt;BR&gt;Scan Thread 0 OSTHread 2f8&lt;BR&gt;Scan Thread 2 OSTHread fcc&lt;BR&gt;Scan Thread 3 OSTHread de8&lt;BR&gt;Scan Thread 4 OSTHread eb8&lt;BR&gt;Scan Thread 8 OSTHread c8c&lt;BR&gt;Scan Thread 12 OSTHread 464&lt;BR&gt;Scan Thread 13 OSTHread 1e0&lt;BR&gt;DOMAIN(0014BF60):HANDLE(Strong):8f15b8:Root:0128d2c0(System.Threading._ThreadPoolWaitOrTimerCallback)-&amp;gt;&lt;BR&gt;01271ff0(System.Net.NetworkInformation.Ping)&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#800080&gt;&lt;FONT color=#000000&gt;We would have hoped that the Dispose() function would have cleaned these objects up, but it didn't.&amp;nbsp; So, what about the GC?&amp;nbsp; Why didn't GC take care of them when dispose didn't? Notice how this gave us the same exact output from the gcroot of the ping class.&amp;nbsp; This must mean that we have a circular reference (ping has a reference to this thread pool object and visa versa) and that is why the GC didn't clean it up. &lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;A class="" title=workaround name=workaround&gt;&lt;/A&gt;
&lt;P&gt;&lt;U&gt;&lt;STRONG&gt;&lt;FONT color=#000000&gt;W&lt;/FONT&gt;orkaround (and reason why calling Dispose didn't clean this up)&lt;/STRONG&gt;&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;The simple workaround to this problem is to cast the object to the IDisposable interface and then call Dispose on that casted object.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;((IDisposable)pingSender).Dispose();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Why does this solve the problem?&amp;nbsp; Take a look at the declaration of the class:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT color=#0000ff&gt;public class Ping:Component,IDisposable&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Notice that it inherits from Component and it also implementes the IDisposable interface.&amp;nbsp; Now lets look at the function declaration for Dispose on the Ping class:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;void IDisposable.Dispose ()&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;In the implementation, the Dispose function was defined as part of the IDisposable interface but the fact that the base class Component also implements a Dispose function was missed.&amp;nbsp; The Ping class doesn't override the Component.Dispose method and so if you call Dispose directly on the Ping object without casting it to an IDisposable Interface, the runtime calls the base class implementation of Dispose&amp;nbsp;instead of the one that was intended (the one for IDisposable).&amp;nbsp;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Note: There is another great blog on debugging managed memory leaks here: &lt;A href="http://blogs.msdn.com/mvstanton/archive/2005/10/11/479861.aspx" mce_href="http://blogs.msdn.com/mvstanton/archive/2005/10/11/479861.aspx"&gt;http://blogs.msdn.com/mvstanton/archive/2005/10/11/479861.aspx&lt;/A&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=505627" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/joncole/archive/tags/Debugging/default.aspx">Debugging</category><category domain="http://blogs.msdn.com/joncole/archive/tags/System.Net/default.aspx">System.Net</category></item></channel></rss>