{"id":232343,"date":"2021-04-16T09:00:00","date_gmt":"2021-04-16T16:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/visualstudio\/?p=232343"},"modified":"2021-04-23T10:40:30","modified_gmt":"2021-04-23T17:40:30","slug":"managed-memory-dump-analyzers","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/managed-memory-dump-analyzers\/","title":{"rendered":"Managed Memory Dump Analyzers"},"content":{"rendered":"<p>For problems that do not manifest in logs or that you cannot investigate by debugging locally you might attempt to capture a diagnostics artifact, like a memory dump, while the issue is active in your production environment. However, upon talking to developers and support engineers we know that memory analysis can be time consuming, complex, and requires a skillset that can take years to perfect.<\/p>\n<p>Our new .NET analyzers have been developed to help identify the key signals in your memory dump that might indicate a problem with your production service. This blog post details how to use Visual Studio\u2019s new .NET Memory Dump Analyzer to find production issues by:<\/p>\n<ul>\n<li>Opening a memory dump<\/li>\n<li>Selecting and executing analyzers against the dump<\/li>\n<li>Reviewing the results of the analyzers<\/li>\n<li>Navigating to the problematic code<\/li>\n<\/ul>\n<h3>Finding async anti-patterns<\/h3>\n<p>Asynchronous (async) programming has been around for several years on the .NET platform but can been difficult to do well. There has been some confusion on the <a href=\"https:\/\/github.com\/davidfowl\/AspNetCoreDiagnosticScenarios\/blob\/master\/AsyncGuidance.md\">best practices for async<\/a> and how to use it properly which has led to some antipatterns that may not reveal themselves until your service is under high load.<\/p>\n<p>We talked to a bunch of support engineers and the \u201csync-over-async\u201d antipatterns have a set of negative performance characteristics:<\/p>\n<ul>\n<li>Service response times are slower than normal.<\/li>\n<li>Increase in the number of requests resulting in timeouts.<\/li>\n<li>CPU and memory tend to remain within normal range.<\/li>\n<\/ul>\n<p>Of course, at this point, there are still a wide range of underlying causes that might be at the heart of your problematic service behavior. Our team wanted to make it easier for developers to find these kinds of issues and also identify where you might remediate the problem.<\/p>\n<p>In pursuit of this goal, we have started developing a new <a href=\"https:\/\/docs.microsoft.com\/visualstudio\/debugger\/how-to-debug-managed-memory-dump\"><strong>.NET Diagnostics Analyzer tool<\/strong><\/a> to help developers, new to dump debugging, quickly identify (or rule out) issues we know impact customers in production environments, let\u2019s look at an example.<\/p>\n<h3>Automatic analysis of a memory dump<\/h3>\n<p>Let\u2019s assume the service has been exhibiting the symptoms we noted earlier (timeouts, slow response times, etc.), how do you go about validating (or invalidating) the possible root cause?<\/p>\n<h4>Open the memory dump<\/h4>\n<p>First, let\u2019s open the memory dump in Visual Studio by using the\u00a0<em>File -&gt;Open -&gt; File<\/em> menu and select your memory dump. You can also drag and drop the dump into the Visual Studio to open it.<\/p>\n<p>Notice on the Memory Dump Summary page a new <strong>Action<\/strong> called <strong>Run Diagnostics Analysis<\/strong>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/1-visualstudio-dump-summary-actions.png\"><img decoding=\"async\" class=\"alignnone wp-image-232346\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/1-visualstudio-dump-summary-actions.png\" alt=\"Visual Studio Dump Summary list of Actions\" width=\"368\" height=\"335\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/1-visualstudio-dump-summary-actions.png 429w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/1-visualstudio-dump-summary-actions-300x273.png 300w\" sizes=\"(max-width: 368px) 100vw, 368px\" \/><\/a><\/p>\n<p>Selecting this action will start the debugger and open the new <strong>Diagnostic Analysis<\/strong> page with a list of available analyzer options, organized by the underlying symptom.<\/p>\n<h4>Selecting and executing analyzers against the dump<\/h4>\n<p>In my example I am concerned with my \u201capp not responding to requests in a timely manner\u201d<em>. <\/em>To investigate these symptoms, I am going to select all the options under <strong>Process Responsiveness<\/strong> as this best matches my app\u2019s issue.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/2-visualstudio-diagnostics-analysis-window.png\"><img decoding=\"async\" class=\"alignnone wp-image-232347\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/2-visualstudio-diagnostics-analysis-window.png\" alt=\"Visual Studio Diagnostics Analysis Window\" width=\"521\" height=\"405\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/2-visualstudio-diagnostics-analysis-window.png 776w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/2-visualstudio-diagnostics-analysis-window-300x233.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/2-visualstudio-diagnostics-analysis-window-768x596.png 768w\" sizes=\"(max-width: 521px) 100vw, 521px\" \/><\/a><\/p>\n<p>Hitting the <strong>Analyze<\/strong> button will start the investigation and present results based on the combination of process info and CLR data captured in the memory dump.<\/p>\n<h4>Reviewing the results of the analyzers<\/h4>\n<p>In the image below the analyzer has found two error results, and upon selecting the first result (\u201cThread pool is out of threads\u201d) I get to see the <strong>Analysis Summary<\/strong> which is proposing that the \u201cCLR thread pool is experiencing starvation\u201d. This information is really important to an investigation, it suggests that the CLR has currently used all available thread pool threads, which in turn means we cannot respond to any new requests until a thread is released.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/3-visualstudio-diagnostics-analysis-results.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-232348\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/3-visualstudio-diagnostics-analysis-results.png\" alt=\"Visual Studio Diagnostics Analysis results\" width=\"1489\" height=\"363\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/3-visualstudio-diagnostics-analysis-results.png 1489w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/3-visualstudio-diagnostics-analysis-results-300x73.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/3-visualstudio-diagnostics-analysis-results-1024x250.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/3-visualstudio-diagnostics-analysis-results-768x187.png 768w\" sizes=\"(max-width: 1489px) 100vw, 1489px\" \/><\/a><\/p>\n<p>Selecting the second results \u201cThread pool is out of threads due to blocked async methods\u201d, reveals the heart of the problem more specifically. By looking at the dump, the analyzer was able to find specific locations where we have inadvertently called blocking code from an asynchronous thread context, and this is leading directly to an exhaustion of thread pools.<\/p>\n<p>The call out in this case is \u201cDo not synchronously wait on Monitors, Events, Task, or any other objects that may block your thread. See if you can update the method to be asynchronous.\u201d. My next job is to find that problematic code.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/4-visualstudio-diagnostics-analysis-results2.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-232349\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/4-visualstudio-diagnostics-analysis-results2.png\" alt=\"Visual Studio Diagnostics Analysis results\" width=\"1495\" height=\"305\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/4-visualstudio-diagnostics-analysis-results2.png 1495w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/4-visualstudio-diagnostics-analysis-results2-300x61.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/4-visualstudio-diagnostics-analysis-results2-1024x209.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/4-visualstudio-diagnostics-analysis-results2-768x157.png 768w\" sizes=\"(max-width: 1495px) 100vw, 1495px\" \/><\/a><\/p>\n<h4>Navigating to the problematic code<\/h4>\n<p>By clicking on the <strong>Show call stack<\/strong> link Visual Studio will immediately switch to the threads that are exhibiting this behavior and the <strong>Call Stack<\/strong> window will show me all the methods that require further examination. I can quickly distinguish between my code (SyncOverAsyncExmple.*) from Framework code (System.*), and I can use this as the starting point of my investigation.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/5-visualstudio-call-stack.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-232350\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/5-visualstudio-call-stack.png\" alt=\"Visual Studio Call Stack\" width=\"1937\" height=\"623\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/5-visualstudio-call-stack.png 1937w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/5-visualstudio-call-stack-300x96.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/5-visualstudio-call-stack-1024x329.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/5-visualstudio-call-stack-768x247.png 768w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/5-visualstudio-call-stack-1536x494.png 1536w\" sizes=\"(max-width: 1937px) 100vw, 1937px\" \/><\/a><\/p>\n<p>Each frame (or row) of a call stack corresponds to a method and by double-clicking on any of the stack frames I prompt Visual Studio to lead me to the code that led directly to this scenario on this thread. Unfortunately I do not have the symbols or the code associated with this application so on the <strong>Symbols not loaded<\/strong> page below I can select the <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/decompilation-of-c-code-made-easy-with-visual-studio\/\">Decompile Source code option<\/a>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/6-visualstudio-decompilation.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-232351\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/6-visualstudio-decompilation.png\" alt=\"Visual Studio Decompilation\" width=\"800\" height=\"458\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/6-visualstudio-decompilation.png 800w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/6-visualstudio-decompilation-300x172.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/6-visualstudio-decompilation-768x440.png 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/a><\/p>\n<p>In the decompiled source below it is clear to me that I have an asynchronous <strong>Task<\/strong> (ConsumeThreadPoolThread) calling a function (DoSomething) that contains a <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/system.threading.waithandle.waitone\">WaitHandle.WaitOne method<\/a>, which is blocking the current thread pool thread until it receives a signal (exactly what I want to avoid!). So to improve the responsiveness of my app I have to find a way to remove this blocking code from all asynchronous contexts.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/7-visualstudio-decompiled-code.png\"><img decoding=\"async\" class=\"alignnone wp-image-232352\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/7-visualstudio-decompiled-code.png\" alt=\"Visual Studio Decompiled code\" width=\"986\" height=\"611\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/7-visualstudio-decompiled-code.png 1200w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/7-visualstudio-decompiled-code-300x186.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/7-visualstudio-decompiled-code-1024x634.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2021\/04\/7-visualstudio-decompiled-code-768x476.png 768w\" sizes=\"(max-width: 986px) 100vw, 986px\" \/><\/a><\/p>\n<h3>Check it out now!<\/h3>\n<p>The new .NET Memory Analyzer tool makes it easier for developers and support engineers to get started debugging and diagnosing issues in memory dumps, allowing them to quickly root cause issues in production environments.<\/p>\n<p>We currently support the following Analyzers with new and improved analysis coming in the very near future:<\/p>\n<ul>\n<li>Finalizer queue<\/li>\n<li>CLR thread pool<\/li>\n<li>Sync over async<\/li>\n<li>Deadlock detection<\/li>\n<\/ul>\n<p>We believe there are many more problematic issues that can be quickly confirmed by using dump analyzers and we are hoping to get community feedback on which ones are the most important to you.<\/p>\n<p><strong>Please <span class=\"\">help us prioritize which analyzer to improve and build next by <a href=\"https:\/\/www.surveymonkey.com\/r\/P2L8M9H\">filing out this survey<\/a>!<\/span><\/strong><\/p>\n<div class=\"row justify-content-center\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>With the release of Visual Studio 2019 16.9 you can try out our new managed memory dump analyzers to help you root cause the issues that plague your applications in production. We&#8217;re excited for you to give it a try!<\/p>\n","protected":false},"author":1017,"featured_media":232346,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[155],"tags":[1665,9,3835],"class_list":["post-232343","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-visual-studio","tag-debugging","tag-debug","tag-diagnostics"],"acf":[],"blog_post_summary":"<p>With the release of Visual Studio 2019 16.9 you can try out our new managed memory dump analyzers to help you root cause the issues that plague your applications in production. We&#8217;re excited for you to give it a try!<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/232343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/users\/1017"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=232343"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/232343\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/232346"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=232343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=232343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=232343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}