一、按钮介绍
1.1 补充
返回断点处:
设置debug配置:
二、增加/切换debugger视图
三、window快捷键
- 所在行处: Ctrl+F8
- 断点属性编辑: Ctrl+Shift+F8
四、一些常用的高级功能
4.1 查看对象内存-Attach memory agent
1.勾选Attach memory agent
2.计算对象大小(但是大小有限制,对象太大,计算不出来)
3.对象太大,可能会报错:
4.成功计算对象大小:
4.2 Set Value的用法
- 可以在网络通信时调试用,因为网络通信的参数不好改,可以通过打断点后Set Value调试;
- 初始化时,比如要观察初始化时,一些行为,老是改配置或值后再启动,效率略低,可以通过通过打断点后Set Value调试;
4.3 Run to Cursor——运行到光标
相当于没打断点,但起到了断点的作用:
4.4 stream流调试-Trace Current Stream Chain
1.Trace Current Stream Chain,调试lambda表达式:
2.有两种模式:
- Flat Mode——把每一步分步骤展示;
- Split Mode——把每一步对象变化展示出来;
3.Flat Mode模式截图:
4.Split Mode模式截图:
5. 总体来说用处比较局限,因为一般通过流处理的对象都比较大,太大了idea就不支持了。
4.5 导出内存快照
4.6 condition
断点处点击鼠标右键:
4.6.1 对变量取模
在for循环中,条件表达式中的i往往要循环多次,点击断点右键即可出现条件面板,当i取模为2时执行debug,这样就可以在调试的时候将程序停在我们想要停的地方。具体如图所示:
4.6.2 调试指定线程
我们在调试的时候,无论是对某个变量或者方法进行调试时,debugger都会表明该断点调试所在的线程。
当我们要指定调试某个线程时,可以在条件面板中指定需要调试的线程名,具体如图所示:
4.7 条件多实例调试
1.设置断点类型为Thread:
- All: 会阻塞所有线程;
- Thread:只会阻塞当前线程
2.设置Allow multiple instances,允许多个实例:
3.最终:
使用All的模式,所有进入代码的线程,都会依次卡在第一个断点上,如果不放行,任意一个线程都不进入到下一步。如果是Thread的模式,那么就会每个线程进行依次进行调试,依次进入各自的断点中。
4.8 Drop Frame-此方法回退到调用处
4.9 打印堆栈信息
我们在调试的时候,除了看代码中的变量、方法的执行过程外,有的时候还想看看与之相关的堆栈信息。
看看代码在运行的同时,堆栈里发生什么变化。
点击断点右键,More(Ctrl+Shift+F8) 调出更为详细的配置面板,勾选“断点信息”与“堆栈”即可。如下图所示:
点击调试后的效果如下图所示:
4.11 避免操作资源(强制返回)
当我们在调试时,如果在某个方法内有许多行代码,而你只想调试其中的某一行代码,不接着往下调试,那么可以选择debug的Force return(强制返回),就可以跳过后面的代码执行直接跳出方法。具体如下图所示:
结果只调试了指定的一行代码,具体效果如下图所示:
五、断点类型与设置
5.1 行断点(line breakpoints)
图标:
无需多言,是我们最常用的断点。
5.2 字段断点(field breakpoints)
图标:
当指定的字段被读取或写入时暂停程序。这允许你对与特定实例变量的交互作出反应。例如,如果在一个复杂的过程结束时,你的某个字段出现了明显的错误值,设置一个字段观察点可能有助于确定故障的来源。该类型断点的图标。
鼠标右键点击该断点图标 ,弹出该断点配置,会有Field access和Field modification选项,此选项是字段类型断点特有的,分别对应访问该字段或修改该字段触发断点,两项同时选中,则访问与修改该字段都会触发断点。
5.3 方法断点(method breakpoints)
图标:
在进入或退出指定的方法或其实现之一时暂停程序,允许你检查该方法的进入/退出条件。
当断点加在class类名这一行,且该类中没有编写构造函数(只有默认无参构造函数),当调用默认
无参构造函数时会触发此断点,程序挂起,故该断点虽然图标是行断点类型图标,但实际上属于方
法类型断点。
鼠标右键点击该断点图标 ,弹出该断点配置,会有Emulated、Method entry、Method
exit选项,此选项是方法类型断点特有的。Emulated勾选中,会将方法断点优化成方法中第一条和最后一条语句的行断点,这样会优化调试的性能,因此在IDE中会默认选中。
通过匹配符批量添加方法断点,在断点列表页:
匹配符示例:
5.4 异常断点(Exception breakpoints)
图标:
- 异常断点分为两种,一种是Any Exception,任意Throwable异常被捕获或未被捕获就会触发断点,另一种是指定类型的异常及其该异常子类被捕获或未被捕获会触发断点;
- 鼠标右键点击该断点图标 ,弹出该断点配置,会有Caught exception和Uncaught exception选项,此选项是字段类型断点特有的,Caught exception选项选中时,当指定的异常被捕获时,触发断点程序挂起,Uncaught exception选中时,当指定的异常未被捕获时,触发断点程序挂起;
六、断点控制
图标:
七、断点属性配置
断点有许多属性配置,如下图所示,下面将会对各个属性的作用以及使用进行说明。
5.1 Enabled
表示是否启用该断点,选中表示启用,取消选中表示不启用。
7.2 Supend
- 当断点的 Suppend 属性被勾选,触发该断点时,会触发程序挂起,当该属性未选中时,程序触发该断点时,程序不会挂起,常用于输出一些表达式结果日志;
- 当断点的 All 属性被勾选,触发该断点时,会挂起所有线程;
- 当断点的 Thead 属性被勾选,触发该断点时,只会挂起触发该断点的那个线程,不影响其他线程。当需要在不暂停程序的情况下记录一些表达式时(例如,需要知道一个方法被调用了多少次时),或者需要创建一个主断点,在击中后启用附属断点时,非暂停性断点是非常有用的。实际生产实践中,可用于调试多线程并发的问题。
7.3 Condition
可以输入一段能获得true或false的表达式,程序运行到断点处,且表达式条件为true才会触发断点。
7.4 Log
下面三个属性选项经常配合 Suppend 属性一起使用,用于在不挂起的情况下,输出一些想要的日志信息。
- Breakpint hit message :控制台输出触发端点的日志信息,类似如: Breakpoint reached at ocean.Whale.main(Whale.java:5) ;
- Stack trace :输出触发断点时的堆栈信息;
- Evaluate and log :计算表达式结果并输出表达式结果到控制台,表达式的计算基于断点所在行的上下文,表达式的语句可以是字符串字面量,如 “我是字符串” ,也可以是方法调用,如users.size() ,也可以是多行语句块,表达式的结果取自return语句,如果没有return语句,会取表达式中的最后一行语句。
7.5 Remove once hit
是否在断点触发后移除该断点,后续不在触发。
7.6 Disable until hitting the following breakpoint
指定在另一个断点触发后,该断点才启用,若该断点启用后,并且被触发。
场景:当只需要在某些条件下或某些操作后暂停程序时,这个选项很有用。在这种情况下,触发断
点通常不需要停止程序的执行,而是做成非暂停状态。
7.7 Filters
前边说的大都数属性,都只针对方法程序运行上下文。此属性更多关注通过过滤掉类、实例和调用者方法来微调断点操作,只在需要时暂停程序。,有如下几种过滤方式:
- Catch class filters :此选项只对异常类型的断点可用,可以让程序只在指定类和子类中抛出的异常才会触发断点或者不在指定的类和子类中触发断点(即排除一些类,排除通常以 - 开始,例如 -pacakge.ClassName );
- Instance filters :只有指定实例id号可以触发断点,多个实例id号以逗号隔开,实例id号可以在Variables和Memory面板中查看;
- Class filters :可以让程序只在指定类和子类中才会触发断点或者不在指定的类和子类中触发断点(即排除一些类);
- Caller filters :根据调用者来进行过滤,需指定方法的全限定名(包含方法签名),例如mypackage.MyObject.addString(Ljava/lang/String;)V;
7.8 Pass count
勾选中并输入一个正整数N,N>=1,那么程序会每N次命中断点才会触发挂起,如果同时设置了condition 与 pass count 属性,ide会优先判断 condition 表达式,再判断 pass count 是否满足,下例中, pass count 中传入的是15,每15次命中断点才会触发断点,挂起程序。
八、远程调试
8.1 打开Idea的 Run/Debug Configurations 新增一个Remote
JVM参数添加 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
8.2 远程项目启动添加参数
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar xxx.jar
8.3 idea启动remote,并打断点调试
九、生产力建议
9.1 使用断点进行 "printf "调试
- 使用非暂停的日志断点,而不是在代码中插入打印语句。这为处理调试日志信息提供了一种更灵活和集中的方式;
- 场景:所有需要打印的地方,生产上禁止 System.out.print();
9.2 调试无响应的应用程序
- 如果你的应用程序挂起,暂停会话,让调试器获得关于其当前状态的信息。然后你可以检查程序的状态并找出问题的原因。
- 场景:项目启动卡死等处理
9.3 测试你的程序是否有并发性问题
- 发现多线程程序在并发方面是否健壮的一个好方法是使用断点,在碰到时只暂停一个线程。停止一个线程可能会揭示出应用程序设计中的问题,否则这些问题就不会显现出来。
9.4 计算保留的大小
对于每个类的实例,你可以计算它的保留大小。保留大小是指对象本身和它所引用的所有对象以及没有被其他对象引用的对象所占据的内存量。
这在估算重型单体或从磁盘上读取的数据(例如,复杂的JSON)的内存占用时,可能很有用。另外,在决定使用哪种数据结构时(例如,ArrayList与LinkedList),这也很有用。
在运行应用程序之前,确保在设置/首选项|构建、执行、部署|调试器中启用附加内存代理选项。
在查看类的实例时,右键单击一个实例并单击计算保留大小。
十、参考文章
IEDA使用之debug技巧(附高级玩法)