”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 调试无响应的应用程序

调试无响应的应用程序

发布于2024-08-14
浏览:264

阅读其他语言:English Português 中文

有许多调试器教程可以教您如何设置行断点、记录值或计算表达式。虽然这些知识本身就为您提供了许多工具来调试应用程序,但实际场景可能会更复杂一些,并且需要更高级的方法。

在本文中,我们将学习如何在没有太多项目先验知识的情况下找到导致 UI 崩溃的代码,并即时修复损坏的代码。

问题

如果您想遵循该示例,请首先克隆此存储库:https://github.com/flounder4130/debugger-example

假设您有一个复杂的应用程序,当您执行某些操作时该应用程序会崩溃。您知道如何重现错误,但困难在于您不知道代码的哪一部分负责此功能。

Depurar Aplicaciones No Responsivas

在我们的示例应用程序中,当您单击按钮 N 时,会发生崩溃。然而,要找到负责此操作的代码并不那么容易:

Depurar Aplicaciones No Responsivas

让我们看看如何使用调试器来找到它。

方法断点

方法断点相对于行断点的优点是它们可以在类的整个层次结构中使用。这对我们的例子有什么用?

如果您查看示例项目,您将看到所有操作类均派生自 Action 接口,并具有单个方法:perform()。

Depurar Aplicaciones No Responsivas

在此接口方法上设置方法断点将在每次调用派生方法之一时挂起应用程序。要设置方法断点,请单击声明该方法的行。

启动调试会话并单击按钮 N。应用程序在 ActionImpl14 上暂停。现在我们知道这个按钮对应的代码在哪里了。

Depurar Aplicaciones No Responsivas

尽管在本文中我们的重点是查找错误,但当您想要了解某些内容在大型代码库中如何工作时,此技术也可以为您节省大量时间。

暂停应用程序

带有方法断点的方法工作得很好,但它依赖于我们了解父接口的一些假设。如果这个假设是错误的,或者我们由于其他原因不能使用这种方法怎么办?

好吧,我们甚至可以在没有断点的情况下做到这一点。单击 按钮 N,当应用程序挂起时,转到 IntelliJ IDEA。从主菜单中,选择运行 | 调试操作 | 暂停程序.

Depurar Aplicaciones No Responsivas

应用程序将挂起,允许我们检查线程和变量选项卡中线程的当前状态。这让我们了解应用程序当时正在做什么。由于它挂起,我们可以识别导致阻塞的方法并将其追溯到调用站点。

这种方法比更传统的线程转储有一些优势,我们很快就会介绍。例如,它以方便的形式为您提供有关变量的信息,并允许您控制程序的进一步执行。

提示:有关暂停程序的更多提示和技巧,请参阅无断点调试和 Debugger.godMode()

线程转储

最后,我们可以使用线程转储,这严格来说不是调试器功能。无论您是否使用调试器,它都可用。

单击按钮N。当应用程序崩溃时,转到 IntelliJ IDEA。从主菜单中,选择运行 | 调试操作 | 获取线程转储.

探索左侧的可用线程,在AWT-EventQueue中您将看到导致问题的原因。

Depurar Aplicaciones No Responsivas

线程转储的缺点是它们仅提供程序在创建时的状态快照。您不能使用线程转储来探索变量或控制程序执行。

在我们的示例中,我们不需要诉诸线程转储。但是,我仍然想提一下这种技术,因为它在其他情况下很有用,例如当您尝试调试在没有调试代理的情况下启动的应用程序时。

了解问题所在

不管调试技术如何,我们都会到达 ActionImpl14。在此类中,有人打算在单独的线程中完成工作,但将 Thread.start() 与 Thread.run() 混淆了,后者在与调用代码相同的线程中运行代码。

IntelliJ IDEA 的静态分析器甚至在设计时警告我们这一点:

Depurar Aplicaciones No Responsivas

在 UI 线程上调用执行繁重任务(或在本例中休眠很多时间)的方法,并阻止该方法直到该方法完成。这就是为什么我们在点击 按钮 N.

后一段时间内无法在 UI 中执行任何操作。

热插拔

现在我们已经找到了错误的原因,让我们纠正问题。

我们可以停止程序,重新编译代码,然后再次运行它。然而,仅仅因为做了一个小更改就重新部署整个应用程序并不总是明智的。

让我们以聪明的方式做到这一点。首先,使用建议的快速修复修复代码:

Depurar Aplicaciones No Responsivas

代码准备好后,点击运行 | 调试操作 | 重新加载更改的类。出现一个气球,确认新代码已到达虚拟机。

Depurar Aplicaciones No Responsivas

让我们回到应用程序并检查一下。单击 按钮 N 不再使应用程序崩溃。

提示:请记住 HotSwap 有其局限性。如果您对扩展的 HotSwap 功能感兴趣,那么看看 DCEVM 或 JRebel 等高级工具可能是个好主意

概括

使用我们的推理和一些调试器功能,我们能够找到导致项目中 UI 崩溃的代码。然后,我们继续修复代码,而不会浪费时间重新编译和重新分发,这在实际项目中可能会很长。

我希望您发现所描述的技术很有用。让我知道你的想法!

如果您对更多与调试和分析相关的文章感兴趣,请查看我的其他一些文章:

  • Debugger.godMode() – 使用调试器破解 JVM 应用程序
  • 调试器缓慢问题排查
  • createDirectories() 有什么问题? - CPU 分析指南
  • 无断点调试

更多精彩敬请期待!

版本声明 本文转载于:https://dev.to/flounder4130/depurar-aplicaciones-no-responsivas-4med?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何使用node-mysql在单个查询中执行多个SQL语句?
    如何使用node-mysql在单个查询中执行多个SQL语句?
    Multi-Statement Query Support in Node-MySQLIn Node.js, the question arises when executing multiple SQL statements in a single query using the node-mys...
    编程 发布于2025-05-24
  • 如何使用Depimal.parse()中的指数表示法中的数字?
    如何使用Depimal.parse()中的指数表示法中的数字?
    在尝试使用Decimal.parse(“ 1.2345e-02”中的指数符号表示法表示的字符串时,您可能会遇到错误。这是因为默认解析方法无法识别指数符号。 成功解析这样的字符串,您需要明确指定它代表浮点数。您可以使用numbersTyles.Float样式进行此操作,如下所示:[&& && && ...
    编程 发布于2025-05-24
  • 如何使用Python理解有效地创建字典?
    如何使用Python理解有效地创建字典?
    在python中,词典综合提供了一种生成新词典的简洁方法。尽管它们与列表综合相似,但存在一些显着差异。与问题所暗示的不同,您无法为钥匙创建字典理解。您必须明确指定键和值。 For example:d = {n: n**2 for n in range(5)}This creates a dicti...
    编程 发布于2025-05-24
  • 您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    在javascript console 中显示颜色是可以使用chrome的控制台显示彩色文本,例如红色的redors,for for for for错误消息?回答是的,可以使用CSS将颜色添加到Chrome和Firefox中的控制台显示的消息(版本31或更高版本)中。要实现这一目标,请使用以下模...
    编程 发布于2025-05-24
  • 如何使用Python有效地以相反顺序读取大型文件?
    如何使用Python有效地以相反顺序读取大型文件?
    在python 中,如果您使用一个大文件,并且需要从最后一行读取其内容,则在第一行到第一行,Python的内置功能可能不合适。这是解决此任务的有效解决方案:反向行读取器生成器 == ord('\ n'): 缓冲区=缓冲区[:-1] ...
    编程 发布于2025-05-24
  • 如何将多种用户类型(学生,老师和管理员)重定向到Firebase应用中的各自活动?
    如何将多种用户类型(学生,老师和管理员)重定向到Firebase应用中的各自活动?
    Red: How to Redirect Multiple User Types to Respective ActivitiesUnderstanding the ProblemIn a Firebase-based voting app with three distinct user type...
    编程 发布于2025-05-24
  • C++中如何将独占指针作为函数或构造函数参数传递?
    C++中如何将独占指针作为函数或构造函数参数传递?
    在构造函数和函数中将唯一的指数管理为参数 unique pointers( unique_ptr [2启示。通过值: base(std :: simelor_ptr n) :next(std :: move(n)){} 此方法将唯一指针的所有权转移到函数/对象。指针的内容被移至功能中,在操作...
    编程 发布于2025-05-24
  • 如何高效地在一个事务中插入数据到多个MySQL表?
    如何高效地在一个事务中插入数据到多个MySQL表?
    mySQL插入到多个表中,该数据可能会产生意外的结果。虽然似乎有多个查询可以解决问题,但将从用户表的自动信息ID与配置文件表的手动用户ID相关联提出了挑战。使用Transactions和last_insert_id() 插入用户(用户名,密码)值('test','test...
    编程 发布于2025-05-24
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-05-24
  • Java中假唤醒真的会发生吗?
    Java中假唤醒真的会发生吗?
    在Java中的浪费唤醒:真实性或神话?在Java同步中伪装唤醒的概念已经是讨论的主题。尽管存在这种行为的潜力,但问题仍然存在:它们实际上是在实践中发生的吗? Linux的唤醒机制根据Wikipedia关于伪造唤醒的文章,linux实现了pthread_cond_wait()功能的Linux实现,利用...
    编程 发布于2025-05-24
  • 可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    [2这里: https://webthemez.com/demo/sticky-multi-header-scroll/index.html </main> <section> { display:grid; grid-template-...
    编程 发布于2025-05-24
  • 如何使用PHP将斑点(图像)正确插入MySQL?
    如何使用PHP将斑点(图像)正确插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call ...
    编程 发布于2025-05-24
  • MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    在两个条件下插入或更新或更新 solution:的答案在于mysql的插入中...在重复键更新语法上。如果不存在匹配行或更新现有行,则此功能强大的功能可以通过插入新行来进行有效的数据操作。如果违反了唯一的密钥约束。实现所需的行为,该表必须具有唯一的键定义(在这种情况下为'名称'...
    编程 发布于2025-05-24
  • 为什么HTML无法打印页码及解决方案
    为什么HTML无法打印页码及解决方案
    无法在html页面上打印页码? @page规则在@Media内部和外部都无济于事。 HTML:Customization:@page { margin: 10%; @top-center { font-family: sans-serif; font-weight: bo...
    编程 发布于2025-05-24
  • PHP SimpleXML解析带命名空间冒号的XML方法
    PHP SimpleXML解析带命名空间冒号的XML方法
    在php 很少,请使用该限制很大,很少有很高。例如:这种技术可确保可以通过遍历XML树和使用儿童()方法()方法的XML树和切换名称空间来访问名称空间内的元素。
    编程 发布于2025-05-24

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3