{"id":4751,"date":"2016-02-15T10:00:00","date_gmt":"2016-02-15T18:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/?p=4751"},"modified":"2019-02-14T15:30:15","modified_gmt":"2019-02-14T23:30:15","slug":"analyze-cpu-memory-while-debugging","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/analyze-cpu-memory-while-debugging\/","title":{"rendered":"Analyze CPU and Memory while Debugging"},"content":{"rendered":"<p>Would you like to learn how to make your code run faster, use less memory, or just find out whether your code has a CPU or memory issue? Of course you would\u2014you\u2019re a developer! But then, memory and performance tuning often suffers from the pitfall of being an \u201cimportant but not urgent\u201d task that you simply can\u2019t seem to get to because of the really urgent stuff. So why not bring that task little closer to you?<\/p>\n<p>In this post we\u2019ll look at how using the debugger-integrated performance and memory tools in Visual Studio 2015 Update 1. Without leaving your debugging workflow, these tools let you quickly answer questions like \u201chow is my memory footprint?\u201d \u201cwhat is using all this memory?\u201d, \u201cshould I be concerned about the performance of this code?\u201d, and \u201cwhy is this so slow?\u201d. Although we show ASP.NET in this post, these tools also work when debugging Windows desktop applications and C#\/VB\/C++ universal Windows applications that target desktop.<\/p>\n<p>If you like what you see in this blog post, please <a href=\"http:\/\/landinghub.visualstudio.com\/perftools\">join our Visual Studio Performance Tools Community<\/a> to stay up-to-date and help steer future features.<\/p>\n<h2>Finding Performance and Memory Problems<\/h2>\n<p>The first step in optimizing the performance of your code is to know where to make improvements. To help with this, PerfTips and the Diagnostics Tools window in the Visual Studio 2015 debugger give you inline, glance-able performance information.<\/p>\n<p>To use PerfTips, just set a breakpoint and step over a line of code, and you\u2019ll see the PerfTip appear to the right of the instruction pointer (the yellow arrow) with the elapsed (wall-clock) time. In this case it tells us that line 57 took 1406ms to run, which is usually a combination of time spent waiting on I\/O (e.g. an HTTP call or reading a file from disk) and time spent executing code on the CPU:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-01.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"PerfTips\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-01.png\" alt=\"PerfTips\" width=\"640\" height=\"123\" border=\"0\" \/><\/a><\/p>\n<p>If this number is higher than you\u2019d like, run the same code a few more times to see if you get consistent results. In many cases, you can <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/y740d9d3.aspx#BKMK_Set_the_next_statement_to_execute\">Click+Drag the instruction pointer (yellow arrow) back to re-run code without having to stop your debug session<\/a>.<\/p>\n<p>To look at your app\u2019s CPU and memory consumption, open the <a href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2015\/01\/16\/diagnostic-tools-debugger-window-in-visual-studio-2015\/\">Diagnostic Tools window<\/a> (<b>Debug &gt; Show Diagnostic Tools<\/b> or <b>Ctrl+Alt+F2<\/b>):<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-02.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Diagnostics tool window showing CPU and memory consumption\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-02.png\" alt=\"Diagnostics tool window showing CPU and memory consumption\" width=\"525\" height=\"480\" border=\"0\" \/><\/a><\/p>\n<p>The Diagnostic Tools window opens by default when you start debugging, and you can leave it open to keep an eye on your app\u2019s CPU and memory consumption whenever you are debugging.<\/p>\n<p>Hover over the CPU and memory graphs and you\u2019ll see a tooltip that shows the application\u2019s private memory and percentage of CPU consumption at any point in time:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-03.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Tooltips showing point-in-time CPU and memory consumption\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-03.png\" alt=\"Tooltips showing point-in-time CPU and memory consumption\" width=\"640\" height=\"295\" border=\"0\" \/><\/a><\/p>\n<p>Above the memory graph you\u2019ll see a timeline of the breakpoints and steps you took so that you can relate CPU and memory consumption to specific sections of code:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-04.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Timeline of breakpoints above the memory graph\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-04.png\" alt=\"Timeline of breakpoints above the memory graph\" width=\"640\" height=\"135\" border=\"0\" \/><\/a><\/p>\n<p>Again, if you see something that is higher than you expect, run the code multiple times to see if you get similar values. Or click on one of the break events (the rectangles) to set the selected time range to that event, which is useful for viewing the detailed CPU usage information shown in the next section.<\/p>\n<p>If you decide to make an improvement, a few more clicks gets you a breakdown of CPU and memory usage to help identify opportunities for improvement. We\u2019ll show you how to do this next!<\/p>\n<h2>Reducing CPU Usage<\/h2>\n<p>When you identify a spike in CPU usage, your first instinct might be to try out a few code alternatives and see which ones use the least amount of CPU. But if you have no idea what the problem might be, or want to verify what code path is causing an issue, click on the <b>CPU Usage<\/b> tab in the Diagnostic Tools window, and then click <b>CPU Profiling<\/b> to start recording the functions that are running on the CPU:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-05.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"CPU Usage tab and CPU Profiling command to start recording\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-05.png\" alt=\"CPU Usage tab and CPU Profiling command to start recording\" width=\"640\" height=\"99\" border=\"0\" \/><\/a><\/p>\n<p>Doing this samples the call-stack on the CPU once per millisecond, which adds a small amount over performance overhead to debugging. It\u2019s generally small enough, however, that you can leave it running during your debugging sessions.<\/p>\n<p>The simplest way to view CPU data is to set breakpoints at the start and end of the section of code of interest, as lines 55 and 65 below. When the debugger hits line 55, press F5 to run that block of code (and notice the PerfTip that appears on line 65!):<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-06.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Setting breakpoints over a section of code to profile\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-06.png\" alt=\"Setting breakpoints over a section of code to profile\" width=\"640\" height=\"217\" border=\"0\" \/><\/a><\/p>\n<p>The Diagnostic Tools window automatically sets the current time selection to the time between these two breakpoints (as if you had clicked on a break event). You can also set the time range selection by clicking and dragging on a CPU spike in the graph. In both cases, the table in the CPU usage tab shows a call-tree filtered to the selected range of time:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-07.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"CPU profiling call tree\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-07.png\" alt=\"CPU profiling call tree\" width=\"640\" height=\"335\" border=\"0\" \/><\/a><\/p>\n<p>The call-tree provides an aggregated view of all of the recorded call stacks. You can expand the nodes in the tree to follow a series of function calls (or portion of a call stack) and see the CPU usage within that code-path under. <b>Total CPU (ms)<\/b> shows the approximate time spent in a given function and all its parent calls; and <b>Total CPU (%)<\/b> provides a percentage breakdown of the <b>Total CPU (ms)<\/b> column.<\/p>\n<p>Here we see that we spent 1067ms in <i>DeserializeDriversJSON<\/i> when it was called by <i>GetDriverList<\/i>, which was in turn called by <i>GetIndividualDriverCached<\/i>, and so on. Right-click on any function and select <b>View Source <\/b>to examine the code and look for ways to reduce calls to that function, or reduce the number of calls it makes to other functions.<\/p>\n<h2>Reducing Memory Consumption<\/h2>\n<p>To view a breakdown of memory usage, open the <b>Memory Usage<\/b> tab in the Diagnostic Tools window and click <b>Take Snapshot<\/b>. By taking a snapshots both before and after an increase in memory lets you to filter the view to see what changed between the two in terms of <b>Objects<\/b> and <b>Heap Size<\/b>:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-08.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Comparing memory usage between two snapshots\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-08.png\" alt=\"Comparing memory usage between two snapshots\" width=\"640\" height=\"178\" border=\"0\" \/><\/a><\/p>\n<p>When you take two or more snapshots, the numbers in parenthases show the differences from the previous snapshot in the table. All the blue text are hyperlinks that open the heap view to see the full set of objects captured in that snapshot, including a <b>Count <\/b>of objects, their <b>Size<\/b>, and the <b>Inclusive Size <\/b>of all instances of that type plus the size of all referenced types:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-09.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Examining objects and memory size in the heap\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-09.png\" alt=\"Examining objects and memory size in the heap\" width=\"640\" height=\"239\" border=\"0\" \/><\/a><\/p>\n<p>In this case, we have 100,025 <i>DocumentResponse.Driver<\/i> objects in our heap totaling about 91MB in size.<\/p>\n<p>Clicking a link in the parentheses lets you analyze the differences more specifically:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-10.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Link to analyze memory differences more specifically\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-10.png\" alt=\"Link to analyze memory differences more specifically\" width=\"640\" height=\"187\" border=\"0\" \/><\/a><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-11.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Analyzing memory differences more specifically\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-11.png\" alt=\"Analyzing memory differences more specifically\" width=\"640\" height=\"192\" border=\"0\" \/><\/a><\/p>\n<p>Sorting by <b>Inclusive Size Diff<\/b> points you to the objects responsible the memory growth between the two snapshots. In this example, the diff view shows 5 new driver objects with ~54MB of memory growth between the two snapshots. The inclusive size of <i>DriverCache<\/i>, <i>Dictionary<\/i>, and <i>List<\/i> objects indicates that they are all possible culprits.<\/p>\n<p>When viewing managed snapshots, you can select an object to view the references to and from objects of that type. The <b>Paths to Root<\/b> tab shows the references that other objects hold to the selected type:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-12.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Paths to Root tab showing object references\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-12.png\" alt=\"Paths to Root tab showing object references\" width=\"640\" height=\"127\" border=\"0\" \/><\/a><\/p>\n<p>Here we see that the <i>DriverCache<\/i> object has a dictionary, which created 5 new references to driver objects between the two snapshots. To jump into <i>DriverCache<\/i> to see what it\u2019s doing, just right-click and select <b>Go to Definition<\/b>.<\/p>\n<p>The <b>Referenced Types<\/b> tab shows objects that the selected type is referencing:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-15-CPU-Memory-13.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Referenced Types tab showing objects and memory\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-15-CPU-Memory-13.png\" alt=\"Referenced Types tab showing objects and memory\" width=\"640\" height=\"104\" border=\"0\" \/><\/a><\/p>\n<p>Here we see that the <i>Driver<\/i> objects added references to 50MB worth of byte arrays, and 2MB worth of strings between the two snapshots.<\/p>\n<p>Similar steps to what we\u2019ve seen here also works for C++ with some small differences. When debugging C++, first <a href=\"https:\/\/blogs.msdn.microsoft.com\/vcblog\/2015\/10\/21\/memory-profiling-in-visual-c-2015\/\">toggle the \u201cHeap Profiling\u201d button<\/a> before you can take snapshots, and instead of using the references list you can view instances of a particular type and then see the allocation stack for each instance.<\/p>\n<h2>Learning More<\/h2>\n<p>These are simple ways you can measure performance and memory of your app in a few minutes the next time you\u2019re using the Visual Studio debugger. Now that you\u2019ve learned the basics, you can learn more by checking out the following posts:<\/p>\n<ul>\n<li><a href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2015\/07\/20\/performance-and-diagnostic-tools-in-visual-studio-2015\/\">Performance and Diagnostic Tools in Visual Studio 2015<\/a><\/li>\n<li><a href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2015\/10\/29\/profile-your-cpu-in-the-debugger-in-visual-studio-2015\/\">Profile your CPU in the Debugger in Visual Studio 2015<\/a><\/li>\n<li><a href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2015\/04\/29\/diagnosing-event-handler-leaks-with-the-memory-usage-tool-in-visual-studio-2015\/\">Diagnosing Event Handler Leaks with the Memory Usage Tool in Visual Studio 2015<\/a><\/li>\n<li><a href=\"https:\/\/blogs.msdn.microsoft.com\/vcblog\/2015\/10\/21\/memory-profiling-in-visual-c-2015\/\">Memory Profiling in Visual C++ 2015<\/a><\/li>\n<\/ul>\n<p>We also encourage you to <a href=\"http:\/\/landinghub.visualstudio.com\/perftools\">join our Visual Studio Performance Tools Community<\/a> for updates about new features, and to give us feedback about these and other performance tools!<\/p>\n<p>&nbsp;<\/p>\n<table style=\"width: 605px\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"205\"><img decoding=\"async\" style=\"padding-top: 0px;padding-left: 0px;padding-right: 0px;border-width: 0px\" title=\"Dan Taylor\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/Dan-Taylor.jpg\" alt=\"Dan Taylor\" border=\"0\" \/><\/td>\n<td valign=\"top\" width=\"400\">\n<p style=\"padding-left: 15px\"><b>Dan Taylor<\/b>, Program Manager, Visual Studio<\/p>\n<p style=\"padding-left: 15px\">Over the past few years Dan has been driving development of the Performance and Diagnostic tools in Visual Studio, including the Diagnostic Tools window, PerfTips, and performance tools for Windows Store and Windows Universal apps. Prior to that he was driving various performance improvements in the .NET Framework and CLR across Windows 8, Windows Phone 8 and Windows Server.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>Would you like to learn how to make your code run faster, use less memory, or just find out whether your code has a CPU or memory issue? Of course you would\u2014you\u2019re a developer! But then, memory and performance tuning often suffers from the pitfall of being an \u201cimportant but not urgent\u201d task that you [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":255385,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1196,472,155,1029],"tags":[237,85,1383,9,185,53,182,12,196],"class_list":["post-4751","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-desktop","category-gaming","category-visual-studio","category-web","tag-net","tag-asp-net","tag-c","tag-debug","tag-node-js","tag-performance","tag-unity","tag-visual-studio","tag-visual-studio-2015"],"acf":[],"blog_post_summary":"<p>Would you like to learn how to make your code run faster, use less memory, or just find out whether your code has a CPU or memory issue? Of course you would\u2014you\u2019re a developer! But then, memory and performance tuning often suffers from the pitfall of being an \u201cimportant but not urgent\u201d task that you [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/4751","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\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=4751"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/4751\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/255385"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=4751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=4751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=4751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}