SuperAPI AI 工具集

java-debugging

编程与开发

查看项目

更新于 10-24 08:17

技能介绍

java-debugging 是一套面向 Java 缺陷排查的调试流程与操作参考,目标是用可复现、假设驱动的方式找到根因,并在日志无法定位问题时安全地接入调试器。

用途与思路 先稳定复现问题,尽量最小化复现路径,阅读堆栈等证据;然后每次只验证一个可证伪的假设,优先选择侵入性最低的工具(日志行或日志点先于断点);最后补充回归测试,并移除调试参数和临时日志。

安全规则 JDWP 只绑定回环地址 127.0.0.1,禁止在可达网络上使用 *:5005;远程主机应通过 SSH 隧道或 kubectl port-forward 访问。运行中的应用使用 suspend=n;suspend=y 仅限绑定回环的本地短时测试。不得在生产环境保留调试代理,因为 JDWP 允许连接者执行任意代码;未经明确指示不要对生产环境附加调试器。JAVA_TOOL_OPTIONS 会被该环境下所有 JVM(构建工具、fork 的测试 JVM、子进程)继承,容易引发端口占用冲突,应把参数限定到需要调试的单个进程。

接入调试器(JDWP) 启动 JVM 示例:java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:5005 -jar app.jar。建议在所有 JDK 版本上显式写 127.0.0.1:5005:裸地址 address=5005 在 JDK 9 之前监听所有网络接口,JDK 9 起仅监听回环;JDK 8 及更早版本可能不遵守 host:port 形式,需配合防火墙或隧道限制访问。

jdb 附加:jdb -attach 127.0.0.1:5005,可用 stop in、stop at、cont、next、step、locals、print、where、catch 等命令。 VS Code(Extension Pack for Java)在 .vscode/launch.json 中配置 type 为 java、request 为 attach、hostName 为 127.0.0.1、port 为 5005。IntelliJ IDEA 通过 Run | Edit Configurations | + | Remote JVM Debug 配置 host 127.0.0.1、port 5005、调试模式 Attach,对话框会显示对应的 JVM 参数。

调试测试与框架 Maven Surefire 单元测试:mvn test -Dmaven.surefire.debug -Dtest=OrderServiceTest。 Maven Failsafe 集成测试:mvn verify -Dmaven.failsafe.debug -Dit.test=OrderIT。 Gradle 测试:gradle test --debug-jvm --tests '*OrderServiceTest'。 Spring Boot(Maven):mvn spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:5005"。 Spring Boot(Gradle):配置 bootRun 后运行 gradle bootRun。 Quarkus 开发模式:mvn quarkus:dev,默认开放 5005 调试端口;-Ddebug=5006 可改端口,-Ddebug=false 可关闭。 Surefire/Failsafe 调试模式和 --debug-jvm 会挂起等待调试器接入,适合本地运行;也可用自定义 agent 字符串替代裸标志。文档给出了在 JDK 26 上对 Gradle 9.7、Maven Surefire 3.5 和 Quarkus 3.40 的监听验证结果:均监听 127.0.0.1;Gradle 7.6.4、8.0.2(JDK 17)、8.5(JDK 21)和 8.14.3 也监听 127.0.0.1。由于 Gradle 传的是裸地址 address=5005,实际绑定地址取决于 JDK:JDK 9+ 为回环,JDK 8 为所有接口(0.0.0.0:5005)。旧版本 Gradle/插件未经验证,建议用 lsof -nP -iTCP:5005 -sTCP:LISTEN 检查,并在共享网络或 JDK 8 上使用显式回环 agent。

Gradle 显式配置(7.6+,Kotlin DSL):对 Test 任务设置 debugOptions 的 enabled、host 127.0.0.1、port 5005、server true、suspend true;BootRun 继承 JavaExec 而非 Test,需在应用 Boot 插件后单独配置(suspend 设为 false)。之后运行 gradle test --tests '*OrderServiceTest' 或 gradle bootRun,不要再用 --debug-jvm。只配置正在调试的任务,避免两个监听器同时占用 5005。Gradle 7.6 之前可在目标任务上使用 jvmArgs("-agentlib:jdwp=...address=127.0.0.1:5005")(本地测试用 suspend=y),不要同时启用 debugOptions 或 --debug-jvm。JDK 8 及更早版本仍需防火墙/隧道防护。

容器与 Kubernetes docker run --rm -p 127.0.0.1:5005:5005 -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" my-app。容器内 agent 必须绑定 *,端口映射才能生效,但这也使同 Docker 网络的其他容器可访问 JDWP;127.0.0.1: 映射只阻断来自其他主机的访问。仅在无不可信容器共享网络的开发机上使用:放在只含该容器的专用用户自定义网络(而非共享默认桥接)中,或让容器内 agent 保持绑定 127.0.0.1 并通过 docker exec/kubectl port-forward 方式转发。Kubernetes 场景仅对开发/预发 Pod 使用 kubectl port-forward pod/<name> 5005:5005。

常见陷阱 热代码替换只替换方法体,增删方法或字段、修改签名需重启(或用 Quarkus dev mode / Spring DevTools)。缺少调试信息:未加 -g 编译的代码会显示变量不可用(Maven 和 Gradle 默认包含)。Heisenbug/竞态:暂停会改变时序,优先用日志点、线程转储或 JFR,只挂起当前线程而非全部线程。异步与响应式代码的堆栈显示调度器帧而非调用方,可用 IDE 异步堆栈、关联 ID 或仅在开发环境使用 Reactor Hooks.onOperatorDebug()。虚拟线程(JDK 21+)数量可能极多,可用 jcmd <pid> Thread.dump_to_file -format=json file.json 获取概览。长时间暂停可能触发 HTTP、数据库或心跳超时,本地需调大超时。调试器求值会调用 toString(),可能触发懒加载或改变状态。

可选的代码导航辅助 若配置了 Copilot CLI 的 lsp 工具,可用跳转定义、查找引用和调用层次辅助追踪执行路径;该功能可选,grep 和阅读代码同样可行。

参考 运行时症状(CPU、内存、死锁、启动慢)可参考 java-diagnostics 技能。官方工具文档优先于本技能,jcmd 文档和 JDK 故障排查指南地址见原文(将链接中的 21 改为所用版本)。关于版本相关行为:Helpful NullPointerException 消息(JEP 358)在 JDK 14 默认关闭(-XX:+ShowCodeDetailsInExceptionMessages),JDK 15 起默认开启。