在 Ubuntu 上排查 Java 程序问题,常见困扰通常不在“能不能调”,而在“该用哪种方式调、前置条件有没有配对”。这篇文章按实际使用频率,把环境准备、jdb 命令行、IDE 图形化调试、远程连接和几类进阶技巧串起来讲清楚,读完后你可以判断什么时候该看断点、什么时候该接远程、什么时候该补日志和性能工具。
先把 Ubuntu 上的 Java 调试环境配好
正式调试前,先确认 Ubuntu 上的 JDK 和调试信息都已经准备妥当。环境没配完整,后面即便能跑程序,也可能看不到行号、变量值不完整,或者 IDE 无法正常附加调试。
安装 JDK 并确认版本
Ubuntu 下可以直接使用系统包管理器安装默认 JDK:

sudo apt update && sudo apt install default-jdk
安装完成后,用下面的命令确认 Java 版本是否可用:
java -version
这一步的意义很直接:先确认运行时存在,后面的编译、调试器和 IDE 才有共同的基础环境。
补齐环境变量
如果需要手动指定 JDK 路径,可以编辑 ~/.bashrc,加入以下内容:
export JAVA_HOME=/usr/lib/jvm/java-版本号-amd64
export PATH=$JAVA_HOME/bin:$PATH
修改后执行:
source ~/.bashrc
JAVA_HOME 里的版本号需要替换成实际安装目录。这样做的目的,是让命令行工具、构建工具和部分 IDE 配置都能稳定找到同一套 JDK。
编译时记得带上调试信息
很多人会忽略这一步,但它直接影响调试体验。编译 Java 源码时,建议显式加上 -g 参数:

javac -g HelloWorld.java
生成的 class 文件会包含更完整的调试信息,后续查看变量值、源码行号映射和单步执行都会更顺畅。
不用 IDE 时,如何用 jdb 做命令行调试
jdb 是 JDK 自带的命令行调试器,适合服务器环境、轻量排错,或者你只想在终端里快速复现和定位问题的场景。界面虽然简单,但断点、单步、变量查看这些核心能力都具备。
启动调试会话
假设要调试的主类是 HelloWorld,可以直接启动:
jdb HelloWorld
进入后就可以在当前会话里下断点、运行程序和查看执行状态。
常用断点与执行命令
jdb 里最常用的一组命令如下:
- 在方法入口设置断点:
stop in HelloWorld.main - 在指定行设置断点:
stop at HelloWorld:7 - 启动程序:
run - 进入方法内部:
step - 按行跳过方法调用:
next - 继续执行:
cont
这套流程基本覆盖了命令行调试的主线:先停住,再观察,再决定是深入方法还是直接越过。
查看变量和当前上下文
程序停在断点后,可以直接查看变量内容。例如:
print a
locals
print a 用来读取变量 a 的值,locals 则会列出当前栈帧中的局部变量。对于没有图形界面的环境,这已经足够完成多数逻辑问题定位。
如果你的目标是快速确认“程序走到了哪一行、某个变量当时是多少”,jdb 依然是 Ubuntu 下很实用的一把小工具。
图形化调试为什么通常更高效
一旦问题稍微复杂一些,IDE 往往比纯命令行更省时间。IntelliJ IDEA 和 Eclipse 都提供了成熟的图形化调试能力,尤其适合多层调用、复杂对象和临时表达式求值这类场景。
设置断点和启动调试
最基本的操作是在代码行号左侧点击,出现红点后即表示断点已生效。
- IntelliJ IDEA:右键包含
main方法的文件,选择 “Debug File” - Eclipse:右键运行入口,选择 “Debug As → Java Application”
这一步和命令行调试的目标一致,区别只是 IDE 把控制流程和运行状态可视化了。
单步执行的几种典型动作
- “Step Into”:进入当前调用的方法内部
- “Step Over”:执行当前行,但不进入调用的方法
- “Step Return”:从当前方法退出,返回上一层调用
这三个动作配合起来,足以覆盖大部分代码跟踪需求。判断标准通常很简单:关心方法内部细节就进入,只关心返回结果就跳过。
变量、表达式和临时修改值
IDE 的优势主要体现在观察效率上:
- 可以在 “Variables” 面板直接查看当前变量值
- 可以通过 “Evaluate Expression”(
Alt+F8)执行表达式,例如a + b - 可以在调试暂停时直接修改变量值,例如把
a从 5 改成 10,观察分支逻辑是否随之变化
这种“停住程序再做假设验证”的方式,在定位条件判断错误、边界值问题和状态流转异常时尤其高效。
程序跑在 Ubuntu 服务器上时,怎么做远程调试
本地调试解决不了所有问题。很多 Bug 只会出现在远程 Ubuntu 服务器上的真实运行环境里,这时就需要启用 JVM 远程调试,再让本地 IDE 连接过去。
启动服务时加入 JDWP 参数
启动 Java 程序时,附加下面这组 JVM 参数:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
这里使用的是 5005 端口,实际可以按需调整。参数的核心含义是:开启基于 socket 的调试通信,并让 JVM 作为服务端等待 IDE 接入。
在 IDE 中连接远程 JVM
以 IntelliJ IDEA 为例,可以在 “Run → Edit Configurations” 中新增 “Remote JVM Debug” 配置,然后填写远程服务器 IP 和端口。保存后点击 “Debug”,就可以把本地调试器挂到远程 Java 进程上。
远程调试适合解决什么问题
它最大的价值,是让你在接近真实环境的条件下观察代码执行过程,而不是只依赖日志猜测问题位置。对环境相关异常、配置差异、线上偶发逻辑错误,这种方式通常比本地复现更直接。
几种值得常用的高级调试技巧
当基础断点已经不够用时,可以继续用条件断点、异常断点、监视点和性能分析工具,把定位范围进一步缩小。

条件断点:只在特定情况下暂停
在 IDE 里右键断点,找到 “Condition” 后输入布尔表达式,例如:
i == 5
这样程序只有在条件满足时才会停下,特别适合循环次数多、分支复杂、问题只在特定输入下出现的场景。
异常断点:直接停在异常抛出处
如果程序经常抛出某类异常,可以添加 Java Exception Breakpoint,例如:
NullPointerException
一旦抛出该异常,调试器会自动暂停,能更快定位异常真正发生的位置,而不是只看到最终打印出来的堆栈。
监视点:追踪字段何时被访问或修改
对于“某个属性被谁改坏了”这类问题,普通断点不一定够用。此时可以右键类属性,选择 “Add Watchpoint”。当该属性被访问或修改时,程序会暂停,适合排查共享状态被意外覆盖的情况。
日志和性能工具仍然重要
断点调试不是唯一手段。对难复现问题,详细日志仍然很关键,可以用 System.out.println 或日志框架(如 Log4j)补充上下文信息。
如果怀疑是资源占用或性能瓶颈,还可以结合系统和分析工具一起看:
top -p $(pgrep -f 程序名)
这个命令可以直接监控目标进程的 CPU 和内存情况。进一步分析时,还可以使用 VisualVM、JProfiler 检查内存泄漏、CPU 占用过高等问题。
综合来看,Ubuntu 下的 Java 调试并没有单一“标准答案”。本地代码问题,优先用 IDE 断点最快;服务器临场排查,jdb 和远程调试更灵活;一旦问题牵涉异常、状态变化或性能,就要把条件断点、监视点、日志和分析工具组合起来使用。







