阅读其他语言: english português 中文
有许多调试器教程可以教你如何设置行断点、记录值或计算表达式。虽然这些知识本身为您提供了许多调试应用程序的工具,但实际场景可能更复杂,需要更先进的方法。
在这篇文章中,我们将学习如何在不太了解项目的情况下找到它 UI 崩溃的代码,并立即修复损坏的代码。
问题如果您想遵循此示例,请先克隆此存储库:https://github.com/flounder4130/debugger-example
假设你有一个复杂的应用程序,当你执行某些操作时,应用程序就会崩溃。你知道如何重现错误,但困难在于你不知道代码的哪一部分负责这个功能。
在我们的示例应用程序中,单击按钮 N 有时会发生崩溃。但是,要找到负责此操作的代码并不容易:
让我们看看如何使用调试器来找到它。
方法断点与行断点相比,方法断点的优点是可以在整个层次结构中使用。这对我们的例子有什么用?
如果你查看示例项目,你会发现所有的操作类别都是从衍生出来的 Action 接口,并且有单一的方法:perform()。
在此接口方法上设置方法断点将在每次调用衍生方法之一时暂停应用程序。如果要设置方法断点,请单击声明该方法的行。
启动调试会话,单击按钮N。应用程序在 Actionimpl14 暂停。现在我们知道按钮对应的代码在哪里了。
虽然我们在本文中的重点是发现错误,但当您想知道如何在大型代码库中工作时,该技术也可以为您节省大量时间。
暂停应用程序断点的方法效果很好,但它是基于我们对父接口的理解。如果这个假设是错误的,或者我们因为其他原因不能使用它呢?
嗯,我们甚至可以在没有断点的情况下做到这一点。单击按钮 N,当应用程序挂起时,转向 IntelliJ IDEA。从主菜单中选择运行 | 调试操作 | 暂停计划.
应用程序将被暂停,允许我们在线程和变量选项卡中检查线程的当前状态。这让我们知道应用程序当时在做什么。由于它被挂起,我们可以识别导致堵塞的方法,并将其追溯到调用站点。
这种方法比更传统的线程存储有一些优点,我们很快就会介绍它。例如,它以方便的形式为您提供变量信息,并允许您进一步执行控制程序。
提示:有关暂停程序的更多提示和技能,请参考无断点调试和 Debugger.godMode()
线程转储最后,我们可以使用线程转储,这不是严格意义上的调试器功能。不管你用不用调试器,都可以用。
点击按钮N。当应用程序崩溃时,转向 IntelliJ IDEA。从主菜单中选择运行 | 调试操作 | 获取线程转储.
在AWT-EventQueue中,探索左侧的可用线程,您将看到问题的原因。
线程转储的缺点是,它们只提供程序创建时的状态快照。您不能使用线程转储来探索变量或控制程序执行。
在我们的例子中,我们不需要诉诸线程存储。然而,我仍然想提到这项技术,因为它在其他情况下也很有用,例如,当您尝试调试在没有调试代理的情况下启动的应用程序时。
了解问题所在无论调试技术如何,我们都会到达 Actionimpl14。在这种情况下,有些人打算在单独的线程中完成工作,但他们会 Thread.start() 与 Thread.run() 混淆后者在与调用代码相同的线程中运行代码。
IntelliJ IDEA 静态分析器甚至在设计中警告我们:
在 UI 调用执行繁重任务的方法(或在这种情况下休眠大量时间)并阻止它,直到它完成。这就是为什么我们点击按钮 N后一段时间内不可能 UI 执行任何操作。
热插拔现在我们已经找到了错误的原因。让我们纠正问题。
我们可以停止程序,重新编译代码,然后再次运行。然而,仅仅因为一个小的变化而重新部署整个应用程序并不总是明智的。
让我们以一种聪明的方式去做。首先,使用建议的快速修复代码:
准备好代码后,点击操作 | 调试操作 | 重新加载更改类别。气球出现,确认新代码已到达虚拟机。
让我们返回应用程序并进行检查。单击按钮 N 不再使用应用程序崩溃。
提示:请记住,HotSwap 有它的局限性。如果你在扩展。 HotSwap 如果您对功能感兴趣,请查看 DCEVM 或 JRebel 高级工具可能是个好主意
概括利用我们的推理和一些调试器功能,我们可以在项目中找到它 UI 崩溃的代码。然后,我们继续修复代码,而不是浪费时间重新编译和分发,这在实际项目中可能需要很长时间。
我希望你能发现所描述的技术非常有用。让我知道你的想法!
如果您对更多与调试和分析相关的文章感兴趣,请查看我的其他文章:
- Debugger.godMode() – 用调试器破解 JVM 应用程序
- 解决调试器速度慢的问题
- createDirectories() 有什么问题吗? - CPU 分析指南
- 无断点调试
请期待更多精彩!
以上是调试无响应应应用程序的详细内容。请关注图灵教育的其他相关文章!