{"id":244445,"date":"2023-12-15T10:10:19","date_gmt":"2023-12-15T18:10:19","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/visualstudio\/?p=244445"},"modified":"2023-12-19T06:55:18","modified_gmt":"2023-12-19T14:55:18","slug":"unlocking-the-secrets-of-managed-memory-dive-into-event-handler-leak-insights","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/unlocking-the-secrets-of-managed-memory-dive-into-event-handler-leak-insights\/","title":{"rendered":"Unlocking the Secrets of Managed Memory: Dive into Event Handler Leak Insights!"},"content":{"rendered":"<p>Event handler leaks have been around for a long time, and they are one of the peskiest issues WPF (Windows Presentation Foundation) developers regularly deal with. You might be thinking: What makes event handler leaks so important? Event handler leaks are easy to cause, all it takes is to forget to unsubscribe to an event. Additionally, they are quite difficult to spot and even trickier to fix.<\/p>\n<p>The new insight added to the Visual Studio <a href=\"https:\/\/learn.microsoft.com\/en-us\/visualstudio\/profiling\/memory-usage?view=vs-2022#memory-usage-insights\">Managed Memory Usage Tool<\/a> introduced in update 17.9 Preview 1 significantly trivializes the process of spotting\/fixing these leaks. It provides information on which objects are leaking and the event it subscribed to.<\/p>\n<h2>What is an Event Handler Leak?<\/h2>\n<p>An object leaks on the heap when it is functionally out of use, but not identified for Garbage Collection. This means that it will unintentionally remain alive in memory. Event handlers are notorious for causing this scenario. This is because event handlers create a direct reference between an object and the event it has subscribed to.<\/p>\n<p><img decoding=\"async\" width=\"513\" height=\"155\" class=\"wp-image-244450 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-1.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-1.png 513w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-1-300x91.png 300w\" sizes=\"(max-width: 513px) 100vw, 513px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Figure 1: UML of pub\/sub model with events in C#<\/strong><\/p>\n<p>In this example, we have a Publisher and Subscriber class. When Subscriber calls Subscribe(publisher), MyEvent will link Publisher and Subscriber in the heap:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/Screenshot-2023-09-05-112650.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-244941 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/Screenshot-2023-09-05-112650.png\" alt=\"Image Screenshot 2023 09 05 112650\" width=\"887\" height=\"161\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/Screenshot-2023-09-05-112650.png 887w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/Screenshot-2023-09-05-112650-300x54.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/Screenshot-2023-09-05-112650-768x139.png 768w\" sizes=\"(max-width: 887px) 100vw, 887px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><strong>Figure 2: Heap view of Figure 1<\/strong><\/p>\n<p>The issue with this is that if Subscriber forgets to unsubscribe, these references remain on the heap, thus leaking Subscriber. The trivial solution here is to simply call the unsubscribe method, but in more complex applications, it is difficult to track an object\u2019s subscriptions and when to unsubscribe. This is where the Memory Analyzer can come in and help developers fix these issues.<\/p>\n<h2>Okay, How Do We Fix it?<\/h2>\n<p>To demonstrate the insight, we will do a walkthrough debugging of a sample WPF app to find an event handler leak:<\/p>\n<p><img decoding=\"async\" width=\"530\" height=\"333\" class=\"wp-image-244451 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-2.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-2.png 530w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-2-300x188.png 300w\" sizes=\"(max-width: 530px) 100vw, 530px\" \/><\/p>\n<p style=\"text-align: center;\"><strong> Figure 3: Sample code of a WPF application<\/strong><\/p>\n<p>In this case, we have a window which subscribes to the dispatcherTimer_Tick event when opened. What the event is doing doesn\u2019t really matter. The important part of this code is where we forget to unsubscribe to the event when the window gets closed:<\/p>\n<h2><img decoding=\"async\" width=\"427\" height=\"107\" class=\"wp-image-244452 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-3.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-3.png 427w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-3-300x75.png 300w\" sizes=\"(max-width: 427px) 100vw, 427px\" \/><\/h2>\n<p style=\"text-align: center;\"><strong>Figure 4: Code that causes event handler leak in the sample WPF app<\/strong><\/p>\n<p>The commenting-out of the unsubscribe statement here is problematic since it no longer unsubscribes properly as the window closes and will cause a leak. To find it, let\u2019s start debugging this app (F5). For simplicity, let\u2019s assume main() properly causes the leak, it opens AdWindow, causing it to subscribe to an event, then closes it.<\/p>\n<p>First, we need the Diagnostic Tools window open. To get to it in a debugging session, go to Debug -&gt; Windows -&gt; Diagnostic Tools.<\/p>\n<p><img decoding=\"async\" width=\"632\" height=\"456\" class=\"wp-image-244453 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-4.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-4.png 632w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-4-300x216.png 300w\" sizes=\"(max-width: 632px) 100vw, 632px\" \/><\/p>\n<p style=\"text-align: center;\"><strong> Figure 5: How to navigate to the Memory Analysis Tool<\/strong><\/p>\n<p>It should look like this when it is open in a debug session:<\/p>\n<p style=\"text-align: center;\"><img decoding=\"async\" width=\"1586\" height=\"830\" class=\"wp-image-244454 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-5.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-5.png 1586w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-5-300x157.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-5-1024x536.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-5-768x402.png 768w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-5-1536x804.png 1536w\" sizes=\"(max-width: 1586px) 100vw, 1586px\" \/><strong>Figure 6: Memory Analysis Tool view in Debugger<\/strong><\/p>\n<p>This window shows the overall size of the heap and the CPU% for the application being debugged. When we click the camera icon to take a snapshot, we can view the heap and access the event handler leak insight by clicking the value under Objects.<\/p>\n<p><img decoding=\"async\" width=\"302\" height=\"106\" class=\"wp-image-244455 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-6.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-6.png 302w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-6-300x106.png 300w\" sizes=\"(max-width: 302px) 100vw, 302px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Figure 7: How to take and view a snapshot<\/strong><\/p>\n<p>Once we are in the heap view of the snapshot, navigate to Insights:<\/p>\n<p><img decoding=\"async\" width=\"1266\" height=\"631\" class=\"wp-image-244456 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-7.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-7.png 1266w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-7-300x150.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-7-1024x510.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-7-768x383.png 768w\" sizes=\"(max-width: 1266px) 100vw, 1266px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Figure 8: How to navigate to the Insights tab<\/strong><\/p>\n<p>We are finally here! In the <a href=\"https:\/\/learn.microsoft.com\/en-us\/visualstudio\/profiling\/memory-usage?view=vs-2022#memory-usage-insights\">Insights Tab<\/a>, we can see the list of leaking event handlers, and we can see that our leaking window shows up. Additionally, we can see the total amount wasted by that leak. Just that one simple example caused a leak of 4.93 KB! This is because the window has a whole subtree of objects it references that also are leaking just from forgetting to unsubscribe.<\/p>\n<p><img decoding=\"async\" width=\"859\" height=\"219\" class=\"wp-image-244457 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-8.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-8.png 859w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-8-300x76.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-8-768x196.png 768w\" sizes=\"(max-width: 859px) 100vw, 859px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Figure 9: Instance view of event handler leaks<\/strong><\/p>\n<p>Additionally, you can filter out all the system code by clicking \u2019Show Just My Code\u2019 to show just AdWindow.<\/p>\n<p>That\u2019s Cool, But What Now?<\/p>\n<p>So far, we have successfully identified the leak in our app. Now if we want to fix it, we can click \u2018View Details\u2019 to see more information on what the issue is and more importantly, how to fix it.<\/p>\n<p><img decoding=\"async\" width=\"654\" height=\"373\" class=\"wp-image-244458 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-9.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-9.png 654w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-9-300x171.png 300w\" sizes=\"(max-width: 654px) 100vw, 654px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Figure 10: Details view of event handler leak<\/strong><\/p>\n<p>This view shows us some critical information about the leak. We can see the address of the object, the event handler that it is holding onto, and most importantly, the object it subscribed to. This conveys that to fix the issue, AdWindow must unsubscribe from DispatcherTimer. Additionally, you can see the reference graph of the AdWindow object. The \u2018Referenced Objects\u2019 tab shows just how many additional objects are leaked due to AdWindow.<\/p>\n<h2>What Else Can We Do?<\/h2>\n<p>If you\u2019ve made it this far, you might be interested in the other uses this insight has. For instance, the detection logic can handle any kind of Event handler. Consider the console app with a publisher and subscriber class from earlier, if we create our own event handler, we can still detect it.<\/p>\n<p><img decoding=\"async\" width=\"411\" height=\"155\" class=\"wp-image-244459 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-10.png\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-10.png 411w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/08\/word-image-244445-10-300x113.png 300w\" sizes=\"(max-width: 411px) 100vw, 411px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Figure 11: Details view of event handler leak with custom event handler type<\/strong><\/p>\n<p><div  class=\"d-flex justify-content-center\"><a class=\"cta_button_link btn-primary mb-24\" href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\" target=\"_blank\">Download Visual Studio Preview<\/a><\/div><\/p>\n<h2>Tell us what you think!<\/h2>\n<p>There are still plenty of improvements to come in future versions of this experience. Please Download the latest <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">Visual Studio Preview <\/a>and provide your feedback. Please raise issues and provide feedback within the Visual Studio with \u201cReport a Problem\u201d or directly at the <a href=\"https:\/\/developercommunity.visualstudio.com\/spaces\/8\/index.html\">Developer Community site<\/a>.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Event handler leaks have been around for a long time, and they are one of the peskiest issues WPF (Windows Presentation Foundation) developers regularly deal with. You might be thinking: What makes event handler leaks so important? Event handler leaks are easy to cause, all it takes is to forget to unsubscribe to an event. [&hellip;]<\/p>\n","protected":false},"author":124115,"featured_media":246372,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[155],"tags":[9,526,6815],"class_list":["post-244445","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-visual-studio","tag-debug","tag-productivity","tag-visual-studio-2022"],"acf":[],"blog_post_summary":"<p>Event handler leaks have been around for a long time, and they are one of the peskiest issues WPF (Windows Presentation Foundation) developers regularly deal with. You might be thinking: What makes event handler leaks so important? Event handler leaks are easy to cause, all it takes is to forget to unsubscribe to an event. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/244445","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\/124115"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=244445"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/244445\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/246372"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=244445"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=244445"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=244445"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}