IDEA 2019 debug 技巧

  • Post author:
  • Post category:其他




IDEA 2019 debug 技巧



一、debug初识

先看下IDEA 2019 里的 debug 界面

在这里插入图片描述

1、Debugger:debug的面板,查看各类东西

2、Console:控制台,查看日志

3、Show Execution Point:单击后跳到此次debug最后执行位置。方便你一顿操作后不知道现在执行到哪个点了。当然,点击Frames最顶那行,也能回到最后位置。

4、Step Over:下一步(遇到调用方法不进入)

5、Step Into:进里面(如果同行有多个可以进入的,会让你移动光标选择进入的方法)

6、Force Step Into:强制进入下一步,不管是什么方法,即使是jdk封装的方法,也会进入

7、Step Out:跳出方法

8、Drop Frame:这是个非常高科技的按钮,是

后悔药

。详细在后面的调试技巧里讲

9、Run to Cursor:运行直到停在光标处(前提是光标前方无断点),方便的功能,可以不打断点停住

10、Evaluate Expression:计算表达式的值,跟watch不同,这是临时的

11、Trace Current Stream Chain:

未知

12、Frames:栈的相关信息,如线程信息,调用链。

详情见后 “Frames”

13、线程的信息,打钩是当前线程,下拉可以看到其他线程信息。

详情见后 “Frames”

14、调用链的信息,指示是怎么调用到当前断点的,双击可以进入对应的代码。

详情见后 “Frames”

15、Return:重新跑一遍debug

16、Resume Program:眼睛一闭运行,直到结束或者遇到下一个断点

17、Pause Program:

未知

,没用过,不重要

18、Stop:停止debug

19、View Breakpoints:查看所有断点。

详细请看后面的 “View Breakpoints”

20、Mute Breakpoints:静音所有断点。可以这么用:不想再在之后的断点中停住,可以点击该按钮运行剩下的代码

21、Get Thread Dump:

未知

,看名字就是得到线程的Dump文件,可以分析内存情况吧

22、Settings:做一些配置。

详细见后续 “Settings”

23、Pin Tab:钉住最前。似乎没什么用,从来不会被遮挡呀。

24、Watch的面板:展示表达式的值的面板,比起Evaluate Expression,可以长久出现,不像Evaluate是临时性查看,下一次debug就没了

25、New Watch:新增watch表达式:可以不在debug过程增加的,也可以右键选择表达式后Add to Watches(这个菜单只有在debug过程才会出现)

26、Remove Watch:删除watch表达式

27、Move Watch Up:上移调序

28、Move Watch Down:下移调序

29、Duplicate Watch:复制一份

30、Show watches in variables tab:在变量的tab页中显示watch表达式。非debug的状态下点击这个图标似乎无反应,只有debug时你会发现变化

31、Layout Settings:设置layout,所谓layout就是那些小面板。可以增加想要的layout,自己搞乱了layout也可以恢复默认。

详细见后续 “Layout Settings”

详细展开各个说明



1、Frames

在这里插入图片描述



1)线程信息:
  • 打红色钩的,是当前线程
  • 非打钩的,是其他线程


2)详情信息:

双引号里的是线程名字,之后@,之后线程ID,之后in group,之后是这个线程归属的组的名字,之后是线程的状态。如:当前线程名是Thread-0,线程ID是477,在名为main的线程组里,RUNNING状态。


有些线程没有 “组” 的信息

,如不知道Finalizer是哪个组的,这可能是比较基础的线程,所以就没有。



3)线程组:

线程组是为了好维护一堆的线程,线程组下面有线程,也可以挂着其他组。

在这里插入图片描述

可看打钩下面的,是追踪点。蓝色底的是debug停住的地方(断点或者光标),可以发现



光标也可以跟断点一样停住

  1. 当前位置,在名叫Stack02的类的myMethod方法的第10行(

    这个类的包名是com.wyf.test.ideadebug

  2. 导致代码运行到这里的,是上一个 “跳点”,即getString方法第11行


    点击getString那行,进入的不是getString方法的开始,是getString里头的 “跳点”
  3. 再往上跟踪,源头是main方法的第16行

可发现,其实上述就是一个debug的跟踪链。

  • 越靠近上面是 “近”,越下面越是 “源头”


  • 每一行是一个跳点



    所谓的

    跳点

    ,其实就是从一个方法跳到另外一个方法的接触点



    (PS:跳点的词是自创。。。专业的叫什么? 入栈点? 进入一个方法叫入栈,出来方法叫弹栈)

总的来说,这个图是一个跟踪链,从main方法16行,导致了getString的调用,在getString的11行导致了myMEthod的调用,在myMethod的10行就是debug停住的地方。



4)技巧

  • 快速回到最后断点的位置

    :双击Frames最上面一行


  • 快速回到断点的位置

    :双击Frames想进入的那行



5)其他补充

有时候Frames的方法名是

<init>

,表示的是类的初始化,即把断点打在类上,停住时显示的内容

在这里插入图片描述



2、View Breakpoints

在这里插入图片描述

这个面板显示了项目的所有断点



常见操作
  • +:新增。可以看到有各种各类的Breakpoints
  • -:删除
  • Group by Package:左起第三个按钮。这个package不知道是什么意思,好像也不是java的 “包”
  • Group by file:按文件分类,有时候可以方便找到断点位置
  • Group by Class:按class分类,方便找到断点位置


其他补充
  • 断点种类和特性:

    • 行断点(line breakpoints)

      即打在代码行的

    • 类断点(官方没这个说法,是我加的)

      打在类上的断点。跟行断点一样,也是出现在

      Java Line Breakpoints

      分类中;圆形。(

      类断点在debug时也是可以停住的,new的时候,静态方法调用不停!

    • 方法断点(method breakpoints)

      是打在方法上的

    • Java Field Breakpoints

      打在字段上行的断点。当字段的值被改变时,断点会停在改变处(通过反射得到字段并进行改变则不会停下)

    • 异常断点(Java Exception Breakpoints)

      发生异常的时候要停下来的断点(图示是闪电标记)

    • JS异常断点(JavaScript Exception Breakpoints)

      估计就是拦截js异常的断点,应该是自动监控的

  • 断点的形状、颜色

    见图,不同种类的断点、不同状态的断点的图示是不一样的。比如圆形、菱形、眼状、闪电状、红色、黄色、问号表示有Condition。其中打在类上的断点的图示和行断点一模一样

  • 疑惑

    • 断点的状态这么多,既然可以删除断点,也可以不删而临时disabled,为什么还要有suspend状态。
    • 类断点:打在类名那行的断点,在静态调用的时候不会停住,在new这个类时会。感觉比较有趣,在这里提下
    • 方法断点,通常打了方法断点,会在启动springboot时被提示如下,建议你取消,那方法断点存在的意义是什么? (方法断点能在方法结束后即使不打断点也会停下来,算不算它存在意义?)

在这里插入图片描述



3、settings

在这里插入图片描述

  • Show Values Inline:如下效果,在代码的右边显示变量的值,确实很方便

    在这里插入图片描述

    多说一句,阿里的Java代码规范不建议使用行注释,实际测试,在debug时会挤占变量值空间,这可能是原因

在这里插入图片描述

  • Show Method Return Values:如下效果

    在这里插入图片描述

  • Auto-Variables Mode:

    未知其功能,自行研究

  • Unmute Breakpoints on Session Finish:就是在debug结束后,恢复不静音。、

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HhJlwh6X-1583991955079)(/Users/stonewang/Library/Application Support/typora-user-images/image-20200311133351083.png)]



4、Layout Setttings

在这里插入图片描述

  • 分割线之前的是可选的 layout,想要就打勾。默认情况下,似乎Threads、Memory、Overhead都没有启用

  • Restore Default Layout:恢复默认,就是你不小心把某些layout关闭了,或显示尺寸调乱了,用这个恢复

    • 如果你找不到你的layout:Watches,可能用Restore也恢复不了。耐心找找,文字很难描述清楚这种情况。

      在这里插入图片描述



二、调试技巧

强调:如果有个方法打了断点,被直接调用,或者是通过反射被调用,都是会停下的。

虽然反射有点像空气一样,那也还是得通过jdk的一些类调用进入的,不会凭空进入

这个调试技巧也很重要:即某个字段的值是何时赋值的。本文提到了,请详细查阅。



1、技巧

  • Drop Frame

    这个是非常强大的功能,是后悔药。对当前方法重来一遍

    如图的例子,



    1. t2.test1();

      停住时,是不能按Drop Frame的,此时还在主干main线程。
    2. 点击Resume Program时,进入test2,我们一顿调试,越过了for循环,此时我们想重新看看v的值,但是v是过了花括号就看不见了。

      此时我们需要后悔药,点击Drop Frame

      ,回到test2方法被调用的地方(即test1那里)


    注意

    :可能需要注意一点,这个 “后悔药”,让你再运行一次,以本代码为例,如果在for循环里进行了入库操作或向mq发消息,那再执行一次,是不是会

    重复执行

    呢? 应该是会的

在这里插入图片描述

  • 新增watch表达式

    Evaluate好用,但是只有一次,可以新增表达式到watch,则可永久查看。

    选中表达式,然后Add to Watches 进行添加(该菜单只有在debug时才出现)

  • 调试时临时改变变量值

    如图,第一次打印是hello的值,截止停在第二次打印,我们在Variables的layout里右键选中

    Set Value

    ,设置后就打印出新值了

    在这里插入图片描述

  • 远程调试

    用本地代码,调试远程的程序。

    远程程序需要开启权限。另外远程部署的程序的代码,要和本地的一致,不然调试时行数对不上。详细配置方法搜索

  • 给断点设置条件,满足条件的时候才会停住

    设置好后,断点图标有个问号

在这里插入图片描述

在这里插入图片描述

  • 堆栈信息的查看方法


    上面对 Frames的layout也讲了一些知识点

    。这里再补充一些。

    • 最上面是当前断点位置,单击后进入当前运行的位置

      不一定是断点的位置,比如你在断点位置继续运行了一行,点击后就回到运行所在行,不是断点所在行。下面依次是调用链,展示了如何一步步运行到当前的。

    • 点击漏斗(Hide Frames from Libraries)可以过滤jar包里的方法

      比如过滤掉各种框架的,当然你自己写的类如果是在jar包里,也是会隐藏掉的。

      另外注意到一个细节,Frames里灰色的是jar包里的,黑色的是非jar里的

      (下图选中状态那行是非jar的代码,实际上是黑的,看不出黑不黑)

    • 放心调试,某个方法A,

      不管A是被直接调用还是通过反射调用,你打断点,都是会停住的

      ,自然也会显示在Frames列表里

    在这里插入图片描述

  • 如果一个类或者接口,有很多子类,我怎么知道接下来执行到哪个子类了呢?


    如果光看代码是比较麻烦的

    ,但是debug时可以断点,停了之后看它真正的类是什么就可确认。或者你可以使用step in。

  • 【重要技能】我怎么知道某个成员变量的值,在何时被赋值,被谁赋值?

    • 可以在变量中打断点,即 Java Field Watchpoints,如果变量值被改变就会在 “赋值的地方” 停下来,赋值处,比如setter方法,该setter无需打断点,只要变量打了断点。(

      但是,但是,但是

      ,通过反射将字段值改变的,不会停下来)

    • 一般如果有setter,可以在setter打断点,停住后跟踪堆栈(

      不好用,PASS

      ,有些赋值不通过setter,例如类内部的方法访问时直接对该变量赋值。有些是通过反射将值set进的)

    • 对于field watchpoints,默认只有变量值被改变时才会触发,对于访问该变量不触发,如下access

      在这里插入图片描述

  • 【操作技巧】右键编辑器里的断点,即可快捷操作断点

    在这里插入图片描述

  • 善用方法断点

    如下在类上打断点,会在进入方法的时候停住,然后点击Resume Program后并不是直接运行出去,会在出去方法前停住。(如下,无论方法有没有返回值,都会在进入和出去的那行停住,有分支的根据具体的条件如flag的值停在

    return "if"

    /

    return "else"

    在这里插入图片描述

  • 善用异常断点

    异常断点不能直接在编辑器添加,要在View Breakpoints面板添加,可以指定拦截指定异常,或者所有异常。当发生异常的时候,会在产生异常的地方停下,有利于分析异常时的变量情况。

    • 添加步骤,在View Breakpoints->+号,如图

    • 异常拦截规则,跟catch一样,比如你监控的是NPE异常,但是实际抛出ArithmeticException,则不停断点;如果你监控IOException,除了IOException,它的子异常FileNotFoundException也是能停断点的;注意Any Exception,似乎会拦截很多奇怪的异常,如IDEA加载时的异常,如

      在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 停在光标处

    可以免去打断点,点击 Run to Cusor,会运行到光标处(相当于在光标处打了断点)

  • step into

    以往运行主干要进入某个方法的分支,都跑进入打断点,其实很麻烦,用这个step into就行了

  • step out

    跳出某个方法回到上一层调用处。好像有时候 “跳不出来”。

    会产生这样的错觉是因为

    如下面的例子:先停在

    t2.test1();

    ,接着Resume Program到达test2停住,这时候点击step out,并不是回到main方法里,而是test1()里,这就是为什么我们总是觉得step out好像跳不出来,总觉得我没有进入过test1怎么会回到这里,因为已经进入了很多层了,它只能跳出上一层。这时可以一层层跳,总是会跳到最初的main方法里的。

    (我们经常调试spring的代码,step out就回到了很多的类似代理的地方,总之觉得乱七八糟的代码)

    在这里插入图片描述

  • 【长时间的疑惑】为什么有时候会发现,我按下Resume Program,按理说应该一路通畅,但是却在花括号结束处停住了,问题我在

    }

    没打断点,为什么停在那边?

    这个我暂时也不能完全理解。只是知道可能是类似把断点打在方法声明上(方法断点),运行到结束时,即使结尾没有断点,它都会停一下。可能是类似的机制吧



版权声明:本文为w8y56f原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。