开发者社区> 慕枫技术笔记> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

同事嫌我改Bug慢,原来是没掌握这些代码Debug技巧

简介: 代码Debug调试是研发工程师日常工作中必不可少的重要组成部分。进行代码Debug调试的目的无非就两个,一个是自我检查代码逻辑是否有问题,便于自己将Bug消灭在测试介入之前;另一个是进行线上问题排查定位,找到实际在跑业务的过程中出现的Bug。
+关注继续查看

引言

代码Debug调试是研发工程师日常工作中必不可少的重要组成部分。进行代码Debug调试的目的无非就两个,一个是自我检查代码逻辑是否有问题,便于自己将Bug消灭在测试介入之前;另一个是进行线上问题排查定位,找到实际在跑业务的过程中出现的Bug。但是无论是哪个目的,高效率的进行代码Debug调试必定会提高我们码代码的效率以及定位问题解决问题的效率,从而实现代码白盒化自我观测。本文主要罗列了10个常用的Debug技巧,可以让我们定位代码问题事半功倍。

Debug调试场景

回到上一步

进行代码调试的过程中,有的时候由于自己点击下一步的速度比较快,可能之前打的断点命中后直接跳过去了进入到某个方法的内部,但是我们还是想看回头看之前断点中的情况,那么此时可以使用这个回到上一步功能即Drop Frame,快速定位到之前的代码运行位置。我们都知道JVM通过栈帧保存方法调用地址的,因此实际上这部分的功能可以理解为舍弃当前的调用栈回到原来的调用处。

image

字段断点

当我们需要知道类中某个属性值到底什么时候被修改的时候,如果要从最起始的地方进行调试实在太过麻烦,因为有的时候我们可能并不知道属性赋值的起始点到底在哪里,特别是在阅读框架源码的时候。那么此时可以尝试在类的字段进行断点,勾选上在属性访问或者属性修改的时候将运行到属性修改发生的地方或者属性被访问的地方,这样可以大大提高我们找到属性修改再沈地方被修改的效率。

image

Stream调试

Lambda表达式是JDK1.8的新特性,在实际的项目编码也会被经常使用到来简化一些循环操作的代码。但是Lambda表达式并不好进行调试,因此不太方便查看stream流内部的值运行情况,此时我们需要借助于Java Stream Debuger这个插件,这样我们在进行stream流debug的时候就可以看到内部各个值执行的流程以及最终结果,方便我们进行问题定位。

image

表达式计算结果查看

在进行Debug的过程中,在代码的右侧一般会默认展示一些变量当前的值,但是对于一些表达式的值并不会默认展示,而我们有的时候需要关注一下表达式在计算过程中的数据是否正确。此时便可以通过鼠标选中需要计算的代码表达式然后结合(Alt+F8)快捷键查看表达式的计算结果。

image

debug筛选条件

在一些循环条件中,比如某个List中有100个String对象,但是我们在调试的时候希望快速找到满足条件的对象,而不是在不关注的对象上面浪费时间进行debug,这个时候我们就可以使用debug筛选条件快速过滤出我们需要的对象,大大提升我们debug的效率。

image

异常断点

进行断点调试的时候,除了阅读框架源码理解技术原理或者熟悉新业务,大部分情况进行断点调试都是出现了异常需要进一步定位具体原因。但是一般情况下当发生异常的时候,抛出来的异常要么被框架捕捉了,进入框架的源码当中,要么被自己业务代码中的try catch捕捉了,影响问题定位。因此我们想要当异常发生的时候可以停在抛异常的地方,方便我们进行问题定位。

1、在任意断点处点击鼠标右键进行更多debug设置,找到Java Exception Breakpoints添加自带的Exception类型或者自定义的业务异常。

image

2、此时进入debug模式运行代码,当代码逻辑产生之前添加的异常类型后,代码会停留在发生异常的地方,这样异常调试就更加方便了。

image

远程调试

在实际的项目开发中,经常会遇到本地调试没毛病,但是部署到预发布环境或者生产环境中就会出现Bug的问题,这个时候我们只能通过远程调试来具体定位问题到底是什么。

1、在debug模式配置中选择Remote模式

image

2、配置远程环境

image

服务以Jar形式运行

在服务启动的时候需要增加启动参数

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar business.jar

服务在Tomcat容器中

tomcat 的bin目录下的catalina.sh文件中增加配置

JAVA_OPTS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'

服务在Docker容器中

需要在dockerfile配置ENTRYPOINT,也就是服务的启动参数。

注意:

远程调试需要确保本地代码合远程代码的完全一致,否则代码行数匹配不上无法达到调试的效果。

强制返回

我们进行debug问题排查,有的时候只是想确认业务逻辑有没有问题,并不想真正去执行一些耗费资源、或者改变数据的操作,那么在这种场景下,我们可以借助于强制返回的功能,不执行方法后面的代码而指定一个返回值来继续后续的业务逻辑debug。

image


从运行结果可以看得出来,加法的代码逻辑实际并没有执行,而是通过强制返回后直接执行了后面的业务逻辑。

image

运行时修改变量

在debug的过程中,有时候我们需要按照我们预想的逻辑进行问题排查定位,这种场景下我们可能需要修改某些变量的值以便于代码走入不同的预想的业务逻辑。通过Alt + F8快捷键修改获取指定变量的值,右键Set Value设置新的值。

image

输入新的变量值后进行回车设置,如此变量值被改变了,原先的业务逻辑发在条件发生改变之后也发生了改变。

image

多线程调试

Idea默认的Debug模式下会阻塞所有的线程,只有当当前的调试线程逻辑走完之后才会进入其他的线程。那如果想要调试多线程场景下的业务逻辑应该怎么办呢? 实际上在设置断点的时候,鼠标右击断点,我们可以选择Thread调试模式。

image

这样我们在Debugger中就可以通过切换不同的线程来进行业务逻辑调试。

image


常用快捷键

1、F8:Step Over 程序执行到下一步。

2、F7:Step Into 进入方法内部。

3、 Alt+Shift+F7:强制进入方法内部,主要针对F7无法进入的方法内部的情况。

4、Shift+F8:进入方法之后,不希望再一步步执行剩下的代码,可以通过此快捷键跳出。

image

5、Alt+F10:如果当前鼠标光标不在代码运行处,通过此快捷键可以将光标回归到代码运行处。

6、Alt+F9:鼠标光标在何处,可以直接通过此快捷键跳转运行到光标处,无需断点。

7、Alt+F8:计算表达式的值,用鼠标选择需要计算的表达式之后,通过此快捷键可以计算表达式的值。

image

8、Ctrl+F5:比如改了某些代码需要重新运行程序,可以使用此快捷键。

9、F9:如果一段代码中打了两个断点,当debug到第一个断点后,按F9后代码运行到第二个断点处,如果再按F9则执行完所有的代码,也就是说如果当前断点后还有断点则可以通过F9跳转,如果没有则执行完代码逻辑。

10、Ctrl+Shift+F8:查看所有的当前所有的断点。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
day06-Debug&基础练习1
day06-Debug&基础练习1
21 0
全网最实用的 IDEA Debug 调试技巧(超详细案例)
Debug 是程序员的开发神器,使用好了可以帮助我们非常高效的工作、学习、排查问题等。毫不客气的说,是决定我们进阶到更高层级的一个重要技能。 今天跟大家分享一下 IDEA 中 Debug 调试的各种奇技淫巧。
118 0
SAP ABAP实用技巧介绍系列之Debug XSLT transformation
SAP ABAP实用技巧介绍系列之Debug XSLT transformation
99 0
83行代码通关攻略|据说看的人都过了
83行代码挑战赛正在进行中,10.24-10.31,等你来战! 目前已有2500+人参赛,和阿里工程师同台竞技,秀出你的代码肌肉,抱走MacBook Pro等精美大奖。
404 0
Try --force to use installed plugin as dependency.
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.
793 0
【Debug 报异常】Debug打断点报错
用DEBUG启动项目,项目中打断点的,然后会报异常   解决方法: 第一步: 项目-->Java编译器-->Classfile Generation 复选框 全部勾选   第二步:   替换当前文件运行的JRE为sun提供的,不能是Eclipse自带的JRE    Wind...
795 0
gif-drawable的使用及详解
下载gif-drawable包和Demo的链接:http://pan.baidu.com/s/1eQxVKRo 本帖原创,转载的朋友请注明转载地址》:http://www.cnblogs.com/zxxiaoxia/     好久没有写博客了,今天来更新一下。
737 0
封装系统自带的Debug
  Unity3d的Debug.Log函数用于打印日志,一般项目中都会对其作如下两件事情:   (1)希望有一个总的开关来控制整个游戏中日志的打印与否;   (2)有的系统会将Log封一层并添加统一的标记,比如Skill模块希望打印的日志格式为[Skill]***。
641 0
#ifdef _DEBUG
引用:http://zhidao.baidu.com/question/165848051.html #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif 这几行代码重新定义默认的 new 操作符为DEBUG_NEW(MFC自己写的一个宏),使得任何通过new新建出来的对象或者内存块都会被记录下来,如果你的程序此后没有释放它们的话,在你退出调试状态时,VC会在输出窗口里面显示出来这些没有被释放的对象或者内存块的信息(这就是所谓的“内存泄露”)。
565 0
+关注
慕枫技术笔记
InfoQ签约作者、CSDN博客专家、专注于架构设计、微服务以及云原生技术分享
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载