{"id":187094,"date":"2021-10-01T09:02:28","date_gmt":"2021-10-01T08:02:28","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=187094"},"modified":"2024-09-09T14:28:39","modified_gmt":"2024-09-09T13:28:39","slug":"unfreeze-your-apps","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/ja\/idea\/2021\/10\/unfreeze-your-apps","title":{"rendered":"Unfreeze Your Apps"},"content":{"rendered":"\n<p>There are a lot of debugger tutorials out there that teach you how to set line breakpoints, log values, or evaluate expressions. While this knowledge alone gives you a lot of tools for debugging your application, real-world scenarios may be somewhat trickier and require a more advanced approach.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/10\/banner.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>In this article, we will look at how to locate code without much prior knowledge of the project structure and APIs, debug hanging applications, and fix faulty code on the fly.<\/p>\n\n\n\n<div class=\"flex-shrink-0 flex flex-col relative items-end\">\n<div>\n<div class=\"pt-0\">\n<div class=\"gizmo-bot-avatar flex h-8 w-8 items-center justify-center overflow-hidden rounded-full\">\n<div class=\"relative p-1 rounded-sm flex items-center justify-center bg-token-main-surface-primary text-token-text-primary h-8 w-8\"><span style=\"font-size: revert;\">If you\u2019d rather watch than read, take a look at this video based on the article.<\/span><\/div>\n<\/div>\n<div>&nbsp;<\/div>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Unfreeze Your Apps: Debugging Tips\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/J1xLWRsnEf0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">The problem<\/h1>\n\n\n<p>If you want to follow along, start by cloning this repository:<br \/><a href=\"https:\/\/github.com\/flounder4130\/debugger-example\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/flounder4130\/debugger-example<\/a><\/p>\n<p>Suppose you have a complex application that hangs when you perform some action. You know how to reproduce the bug, but the difficulty is that you don\u2019t know which part of the code is in charge of this functionality.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/sophisticated-app-1.png\" alt=\"UI freezes when you click Button N\" width=\"400\" \/><\/p>\n<p>In our example app, the hanging happens when you click <b>Button N<\/b>. However, it is not so easy to find the code that runs when you do that:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/find-in-path.png\" alt=\"Find in Path yields no results when searching for Button N\" width=\"602\" \/><\/p>\n<p>Let\u2019s see how we can use the debugger to find it.<\/p>\n\n\n<h1 class=\"wp-block-heading\">Method breakpoints<\/h1>\n\n\n<p>The advantage of method breakpoints over line breakpoints is that they can be used on entire hierarchies of classes. How is this useful in our case?<\/p>\n<p>If you look at the example project, you\u2019ll see that all action classes are derived from the <code>Action<\/code> interface with a single method: <code>perform()<\/code>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/method-breakpoint-0.png\" width=\"297\" alt=\"Method breakpoint is set at the perform() interface method\"><\/p>\n<p>Setting a method breakpoint in this interface method will suspend the application whenever one of the derived methods is called. To set a method breakpoint, just click the line that declares the method.<\/p>\n<p>Now start the debugger session and click <b>Button N<\/b>. The application gets suspended in <code>ActionImpl14<\/code>. Now we know that this is where the code corresponding to this button is located.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/method-breakpoint-suspend.png\" width=\"556\" alt=\"The application is suspended in the implementation of the interface.\"><\/p>\n<p>Though in this article we are focused on finding the bug, this technique can also save you a lot of time when you want to understand how something works in a large codebase.<\/p>\n\n\n<h1 class=\"wp-block-heading\">Pause application<\/h1>\n\n\n<p>The approach using method breakpoints works well, but it is based on the assumption that we know something about the parent interface. What if this assumption is wrong, or we cannot use this approach for some other reason?<\/p>\n<p>Well, we can even do it without breakpoints. Click <b>Button N<\/b>, and while the application is hanging, go to IntelliJ IDEA. From the main menu, select <b>Run<\/b> | <b>Debugging Actions<\/b> | <b>Pause Program<\/b>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/pause-app-0.png\" width=\"628\" alt=\"You can examine threads in the Debugger tab\"><\/p>\n<p>The application will be suspended, and we can examine the current state of the threads in the <b>Debugger<\/b> tab. This gives us an understanding of what the application is doing at the moment. Since it is hanging, we can identify the hanging method and trace back to the call site.<\/p>\n<p>This approach has some advantages over a more traditional thread dump, which we\u2019ll cover shortly. For example, it gives you information about variables and reflects the current state of the application, allowing you to resume it at any time.<\/p>\n\n\n<h1 class=\"wp-block-heading\">Thread dumps<\/h1>\n\n\n<p>Finally, we can use a thread dump, which is not strictly a debugger feature. It is also available when just running the application.<\/p>\n<p>Click <b>Button N<\/b>, and while the application is hanging, go to IntelliJ IDEA. From the main menu, select <b>Run<\/b> | <b>Debugging Actions<\/b> | <b>Get Thread Dump<\/b>.<\/p>\n<p>Scan through the available threads on the left, and in <b>AWT-EventQueue<\/b> you\u2019ll see what is causing the problem.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/analyze-thread-dump.png\" width=\"1346\" alt=\"Thread dump in the Debugger tool window\"><\/p>\n<p>\nThe downside of thread dumps is that they only provide a snapshot of the program state at the time when they were made. You can\u2019t use thread dumps to explore variables or control the program\u2019s execution.\n<\/p>\n<p>\nIn our example, we don\u2019t need to resort to a thread dump. However, we still wanted to mention this technique as it may be useful in other cases, like when you are trying to debug an application that has been launched without the debug agent.\n<\/p>\n\n\n<h1 class=\"wp-block-heading\">Understanding the issue<\/h1>\n\n\n<p>Regardless of the method used, we arrive at <code>ActionImpl14<\/code>. In this class, someone intended to perform the work in a separate thread, but confused <code>Thread.start()<\/code> with <code>Thread.run()<\/code>, which runs the code in the same thread as the calling code.<\/p>\n<p>IntelliJ IDEA\u2019s static analyzer even warns us about this at design time:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/thread-run-inspection.png\" width=\"580\" alt=\"An inspection warns about suspicious call to Thread.run()\"><\/p>\n<p>A method that does heavy lifting (or heavy sleeping in this case) is called on the UI thread and blocks it until it finishes. That\u2019s why we cannot do anything in the UI for some time after we click <b>Button N.<\/b><\/p>\n\n\n<h1 class=\"wp-block-heading\">HotSwap<\/h1>\n\n\n<p>Now that we\u2019ve discovered the cause of the bug, let\u2019s fix the issue.<\/p>\n<p>We could stop the program, recompile the code, and then rerun it. However, it is not always convenient to redeploy the entire application just because of a small change.<\/p>\n<p>Let\u2019s do it the smart way.  First, correct the code:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/correct-the-code.png\" width=\"678\" alt=\"Correcting the code in the editor\"><\/p>\n<p>After the code is good to go, click <b>Run<\/b> | <b>Debugging Actions<\/b> | <b>Reload Changed Classes<\/b>. A balloon appears, confirming that the new code has made its way to the VM.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/hotswap-balloon.png\" width=\"308\" alt=\"A balloon appears at the Debugger tool window tab.\"><\/p>\n<p>Let\u2019s go back to the application and check. Clicking <b>Button N<\/b> no longer hangs the app.<\/p>\n<p>Keep in mind that HotSwap has its <a href=\"https:\/\/www.jetbrains.com\/help\/idea\/altering-the-program-s-execution-flow.html#reload_classes\" target=\"_blank\" rel=\"noopener\">limitations<\/a>. There are tools like DCEVM or JRebel that offer extended HotSwap capabilities. If you are interested, you can read more about them.<\/p>\n\n\n<h1 class=\"wp-block-heading\">Summary<\/h1>\n\n\n<p>Using our reasoning and a couple of debugger features, we were able to locate the code that was causing a UI freeze in our project. We also learned how the <i>Pause<\/i> feature and thread dumps can be useful in cases where an app is not responding. Finally, we fixed the code without wasting any time on recompilation and redeployment, which can be lengthy in real-world projects.<\/p>\n<p>In this article, we just scratched the surface of how the debugger can be useful beyond a classic Hello World case. If you are interested in any particular topic related to the debugger or other IntelliJ IDEA features, let us know in the comments and feel free to peruse the <a href=\"https:\/\/www.jetbrains.com\/help\/idea\/debugging-code.html\" target=\"_blank\" rel=\"noopener\">documentation<\/a>.<\/p>\n<p>Happy developing, and stay tuned for more!<\/p>","protected":false},"author":1206,"featured_media":73920,"comment_status":"open","ping_status":"closed","template":"","categories":[4759,601],"tags":[632,264,263,2981,3381,667],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/187094"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/users\/1206"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/comments?post=187094"}],"version-history":[{"count":11,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/187094\/revisions"}],"predecessor-version":[{"id":508966,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/187094\/revisions\/508966"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/media\/73920"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/media?parent=187094"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/categories?post=187094"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/tags?post=187094"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/cross-post-tag?post=187094"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}