断点不只是点一下
IDEA 里最常用的当然是在行号左边点一下生成的红点断点,但它只是入门。真正提高效率的是另外几种:
- 方法断点:点在方法签名那一行,菱形图标,能看清方法进出和参数;
- 字段断点:点在成员变量上,字段被读写时停下来,排查“谁把值改了”特别有用;
- 异常断点:
Run → View Breakpoints → Java Exception Breakpoints,填上异常类名,抛出时自动停,比在 catch 里猜位置快得多。
调试快捷键记住四个就够:F8 单步跳过,F7 单步进入,Shift + F8 跳出当前方法,F9 继续运行到下一个断点。
条件断点与日志断点
循环一万次,只想看第 500 次的数据,普通断点会让人按到手酸。右键断点,在 Condition 里填 i == 500,只有条件成立才会停。
更省事的是日志断点:勾选 Evaluate and log,填一句 "user=" + user.getName(),线程不会停,控制台直接输出。它相当于临时插了一行日志,又不用改代码、不用重启,排查偶发问题时特别好用。
条件表达式要小心副作用,比如写 list.remove(0) 当条件,每命中一次就真的删一个元素,调试行为会影响业务结果。
变量面板与 Evaluate
断住之后,Variables 面板能看到当前栈帧里的所有变量,展开集合和对象可以逐层看字段。Watches 可以把关心的表达式钉住,单步时一直显示。
Alt + F8 打开 Evaluate Expression,可以执行任意表达式:调 getter、算 list.size()、甚至调用某个 Service 的方法。注意它执行的是真实代码,带写操作的调用会真的改数据,生产环境远程调试时尤其要克制。
远程调试
本地复现不了的问题,只能连到测试环境或预发环境调试。启动时加 JDWP 参数:
# JDK 8
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 \
-jar app.jar
# JDK 9 及以上,*:5005 表示监听所有网卡
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 \
-jar app.jar
然后在 IDEA 里新建 Remote JVM Debug 配置,填上目标机器 IP 和端口即可。suspend=n 表示不等调试器连上就继续启动;写成 y 的话,应用会一直卡在启动阶段等人 attach,在服务器上很容易被误判成“服务起不来”。
远程调试端口等于一个后门,只在内网、临时排查时打开,用完立刻去掉参数并重启。
常见坑
1. 断点变成灰色打不上
灰色空心圆表示断点无效,常见原因是类还没被加载、源码行号和 class 对不上、或者断点打在了接口方法上。先确认请求真的走到了这个类,再 Build → Rebuild Project 重新编译。
2. 源码和运行的 jar 不是同一版
现象是断点停在了“看起来不该执行”的行,变量值也莫名其妙。远程调试时尤其常见:本地代码改过但没重新打包,服务器跑的还是旧 jar。核对提交号和构建时间,重新打包再试。
3. 远程调试连不上
先在服务器上确认 Java 进程的参数里有 jdwp,再用 ss -lntp | grep 5005 看端口是否监听。绑定成 127.0.0.1:5005 时只能本机连;容器里跑的应用还要把 5005 映射出来,并检查防火墙和安全组。
4. suspend 设成了 y
服务启动即挂起,日志停在 banner 之后不动,看起来像启动失败。排查启动问题时用 suspend=n,需要调试初始化逻辑时再临时改成 y。
5. 在调试器里改了线上数据
Evaluate 和 Set Value 都是真实执行。远程环境调试前先确认数据可以回滚,不要随手调用删除、支付、发消息这类方法。
排查步骤
- 断点不生效:看断点图标是否变灰,确认类已加载、代码已重新编译;
- 断点停不住:检查请求路径有没有走到目标方法,必要时在 Controller 入口先加一个断点;
- 远程连不上:查启动参数、端口监听、防火墙、容器端口映射四件事;
- 启动卡住:确认
suspend=n,并检查是否有死锁或阻塞的初始化逻辑; - 调试完记得移除 JDWP 参数,别把调试端口长期留在服务器上。
评论