高级程序员应该掌握的技能 - debug系列 第一篇

2021/05/18

这个系列文章是高级程序员应该掌握的技能之debug系列,分为2篇,第一篇介绍debug基础、概念介绍,第二篇介绍debug的相关实现原理。

![picture 12(/assets/images//02d8588de41b80b76ab0355d0b7b6f47776b99c5f535a317471124e8fe67348f.png)

本篇主要讲解debug的作用、常用debug流程、debug操作介绍。文章以Java语言和IDEA编辑器为例。

debug的作用

debug是开发者要熟练掌握的工具。debug最重要的作用是帮助我们快速发现、解决程序中的bug。另外debug还可以帮助我们了解程序运行流程,了解程序内部实现。

常见的debug流程

通常debug的流程是

  1. 设置断点
  2. debug模式启动程序
  3. 程序执行触发断点
  4. 在断点处观察程序状态、控制程序运行
  5. 发现问题、修改代码,重新进行第2步

熟悉IDE debug界面

下面以Jetbrains IDEA为例介绍一下IDE中的debug相关的UI界面

![picture 3(/assets/images//624851295fa1b6a9b094fd515c79771f42d74f627031f70b27a31bb1d68d9825.png)

如上面截图所示,

1) debug按钮,通过这个运行的程序具备debug能力。快捷键Control+Shift+D或Alt+Control+D 2) 侧边的Run/Debug按钮,点击,可以选择debug运行。会在具有main方法或unittest的类中显示。IDEA中对应的快捷键是Control+Shift+D(以下快捷键以macos keymap为例,也可以自定义设置) 3) 断点, 在行号上点击可以设置和取消设置断点,断点是指可以中断程序执行的位置。设置和取消设置断点的快捷键是Command + F8 4) Inline variable, 内联变量,可以在代码旁边展示出当前的局部变量的信息,查看状态很方便。 5) Debug window, 这个是debug的控制台和状态展示窗口。查看和关闭debug window的快捷键是Command+5 6) Show execution point,可以重新定位到程序执行的位置,例如我们停在断点后去看相关代码,想快速回到程序位置,可以使用这个按钮,快捷键是Alt+F10。 7) Step over,单步执行,在程序暂停到断点后,通过step over可以让程序运行到当前方法的下一行代码,如果方法执行完则会退出当前方法,快捷键是F8 8) Step into, 如果当前代码行内有其他方法的调用,通过step into 可以进入到这个方法内部。如果这一行代码有多个方法调用,则IDEA会有高亮提示有哪些方法可以step into,我们可以用tab选择回车确认,或者用鼠标点击选择确认。快捷键是F7。Step into会跳过一些系统类,可以在Preferences->Build,Execution,Deployment->Debugger->stepping中配置。 9) Force step into是强制step into,上面的会跳过一些系统类,如果我们想了解这些类的内部执行过程,可以通过Force step into来进入。快捷键是Alt+Shift+F7 10) Step out,如果想跳出当前方法,可以通过Step out(Shift+F8)来跳出并回到调用这个方法的方法内部 11) Drop frame, 这个也是一个很有用的功能,比如我们在debug一个方法时,方法执行了一半,想重新执行这个方法,则可以通过Drop frame丢弃调当前方法栈,重新执行这个方法。不过这个并不是严格意义上的回退,程序的状态是不会回退的,只是重新执行了这个方法。 12) Run to cursor, 通过Run to cursor可以让程序继续执行到当前光标所在的行停下来。注意如果在中间的路径中有其他断点,则会在提前的断点停下,如果想强制跳到当前行,可以通过Force run to cursor(Alt+Command+F9)来实现。快捷键是Alt+F9。 13) Evaluate expression,可以执行函数表达式,比如我们想提前查看下面某个方法的结果,则可以通过这个evaluate功能执行这个方法,很方便。快捷键是Alt+F8 14) Resume program,可以恢复程序,程序会继续执行直到下一个断点或结束。快捷键是Alt+Command+R 15) Pause program, 可以在任意时刻暂停程序,有时我们不知道在哪里设置断点,则可以在程序运行时设置断点查看现在程序在执行什么。 16) Stop program, 停止程序,快捷键是Command + F2 17) Mute breakpoints, 有时候我们不想断点了,希望程序顺利执行,也不希望手动把所有的断点删除,则可以通过Mute breakpoints来临时关闭断点,再次点击可以重新打开。 18) Thread frame, 这里可以看到当前线程栈的信息 19) variables, 可以看到局部变量的数据信息 20) watches, 有时我们想看的变量的信息的层级比较深,或者需要特定的运算才能得到,则可以放到watches以便随时看到这些变量的值。 21) memory, 这里可以看到当前JVM堆内存中的所有加载的类的信息和实例的数量,并且可以查看每个类的实例的具体的信息,非常强大。

熟悉了IDE中的各个功能后,我们基本上就掌握debug的大部分常用操作了。 下面针对一些比较实用的附加功能介绍一下。

设置断点

断点除了最基础的固定在某一行停止,还支持设置表达式。在断点上点击右键,就可以编辑断点属性设置表达式了。 ![picture 4(/assets/images//004ba37bb7258208689fb175063e34bfdd32cc43b0b635c4c68f3af4f73df04f.png)
例如我们只想在某些用户id请求过来时才断点,则可以通过condition设置 userId == 123,userId是当前上下文可以访问到的变量。 另外我们也可以让断点不中断程序执行,并且执行表达式输出结果。 ![picture 5(/assets/images//0100555bf7c8f2b095e33715ee9fa73ad73bbd72afd7dd974eef4c1484bbe7ab.png)

控制程序

除了上面提到的step相关的操作,IDEA还提供了很多使用的控制操作。

Force return: 可以控制当前方法直接返回特定结果,方便我们测试特定case

![picture 7(/assets/images//36196b1ebaec8c412f631eca174619c304b29e75992fc529403edee54a42a92f.png)

Throw exception: 控制当前方法抛出特定异常

![picture 6(/assets/images//dd19246950344ebfbba173e923f1c7bf1eef72f6d84b0e702ef19c080a40411b.png)

hotswap

IDEA中集成了jvm提供的hotswap功能,可以修改方法的方法体。当我们发现bug修改代码后,可以不重启就可以实现程序更新,非常使用。 在debug模式下,修改完代码,编译之后,IDEA就会弹出提示让我们确认是否进行reload。 ![picture 8(/assets/images//76123995f735f3594f36e82052a4788098b6f3b20dbb614cb42eea66cfc08a1c.png)
注意reload只能修改方法体,不能对类进行结构修改。

远程debug

有时我们要debug的程序并不在本地或IDEA内运行,则我们可以通过远程debug来进行debug。

点击Edit configuration,添加一个remote jvm debug类型的configuration ![picture 9(/assets/images//950c5a0cb89d07a0647a4174e1a8a82fefba4c6e5bebf1dcdda0e4eca7eac3ae.png)

![picture 10(/assets/images//93f38612fd6b46fe726e02d44ec111889a6d71eddae9c7e012a77f4c0453fd9f.png)

复制这段代码加到远程的进程的启动参数中启动对应的Java程序,然后把Host换成对应的进程所在机器的hostname或ip,点击Apply ok,再点击这个debug configuration就可以进行远程debug了,其他步骤和本地debug相同。

![picture 11(/assets/images//76873102d88e53379a59b8311eff74937664c1b0f390c55aaa27fefe545312f3.png)

Post Directory