问题记录
attach 成功后搜索字节码文件,点击 create class 时报错
java.io.IOException: No such file or directory 复制代码
错误原因:权限不够
解决方案:
1、首先尝试修改 jdk/bin 文件夹的权限,尝试无效;
2、命令改为:sudo jhsdb hsdb,最后成功得到字节码文件,然后去 jdk/bin 文件夹下可以看到一个新的文件夹,里面存放了我们想要的字节码文件。
JDB
Java调试器(JDB)是Java类在命令行中调试程序的工具。 它实现了 Java 平台调试器体系结构。 它有助于使用Java调试接口(JDI)检测和修复 Java 程序中的错误。
作为开发,我们都在本地调试过项目,一般都使用 IDEA 等工具,方便快捷。那如果没有 IDEA、Eclipse 等工具时,只给你一份代码和配置好的 Java 环境,又该如何进行调试呢?
JDB使用
验证 JDB 安装
% jdb -version 这是jdb版本 9.0 (Java SE 版本 9.0.4) 复制代码
JDB 语法
jdb [ options ] [ class ] [ arguments ] 复制代码
它从 Java Development Kit 调用 jdb.exe。
- options
其中包括用于以高效方式调试Java程序的命令行选项。 JDB启动程序接受所有选项(例如-D,-classpath和-X)以及一些其他高级选项,例如(-attach,-listen,-launch等)。执行 jdb -help 可以看到各参数详细介绍,该部分最为重要。
- class
在其上执行调试操作的类名。
- arguments
这些是在运行时为程序提供的输入值。 例如,arg [0],arg [1]到main()方法。
调试命令
执行 help 可以查看所有可执行的命令,介绍一下常用的命令:
1、添加断点
stop at com.msdn.MyClass:22 stop in com.msdn.MyClass.<init>#构造函数 stop in com.msdn.MyClass.<clinit>#静态代码块 复制代码
需要注意的是上述语句在 windows 上可以执行,mac 上不需要包名,直接使用文件名。
2、调试
step #执行当前行 step up #一直执行, 直到当前方法返回到其调用方 stepi #执行当前指令 next #步进一行 (调用) cont #从断点处继续执行 复制代码
3、查看变量
print <expr> #输出表达式的值 dump <expr> #输出所有对象信息 eval <expr> #对表达式求值 (与 print 相同) set <lvalue> = <expr> #向字段/变量/数组元素分配新值 locals #输出当前堆栈帧中的所有本地变量 复制代码
4、其他
list [line number|method] -- 输出源代码 use (或 sourcepath) [source file path] #显示或更改源路径(目录) run #运行 复制代码
本机调试
进入 class 文件所在目录
jdb -XX:+UseSerialGC -Xmn10M com.msdn.java.hotspot.hsdb.HeatTest2 --启动jdb,可带参数 复制代码
在 windows 上可以用上述带包名的形式进行调试。
jdb -XX:+UseSerialGC -Xmn10M HeatTest 复制代码
在 Mac 上不需要包名。
测试案例
注意:Java 文件不需要包名,打开命令行窗口进入该文件所在目录,然后进行之后的操作。
public class HeatTest2 { private static Test heatStatic = new Test(); private Test heat = new Test(); public void generate() { Test heatWay = new Test(); } public static void main(String[] args) { HeatTest2 heatTest = new HeatTest2(); heatTest.generate(); } } class Test { private String name; } 复制代码
首先编译 Java 源文件,
javac -g HeatTest2.java 复制代码
进入 class 文件所在目录,然后启动 JDB
jdb -XX:+UseSerialGC -Xmn10M HeatTest2 > help #执行 help 可以查看所有可执行的命令,这里就不一一列举了 > stop in HeatTest2.main 正在延迟断点HeatTest2.main。 将在加载类后设置。 > run 运行HeatTest2 设置未捕获的java.lang.Throwable 设置延迟的未捕获的java.lang.Throwable > VM 已启动: 设置延迟的断点HeatTest2.main 断点命中: "线程=main", HeatTest2.main(), 行=19 bci=0 19 HeatTest2 heatTest = new HeatTest2(); main[1] step > 已完成的步骤: "线程=main", HeatTest2.<init>(), 行=8 bci=0 8 public class HeatTest2 { main[1] step > 已完成的步骤: "线程=main", HeatTest2.<init>(), 行=11 bci=4 11 private Test heat = new Test(); main[1] next > 已完成的步骤: "线程=main", HeatTest2.main(), 行=19 bci=7 19 HeatTest2 heatTest = new HeatTest2(); main[1] next > 已完成的步骤: "线程=main", HeatTest2.main(), 行=20 bci=8 20 heatTest.generate(); main[1] next > 已完成的步骤: "线程=main", HeatTest2.main(), 行=21 bci=12 21 } main[1] next > 应用程序已退出 复制代码
如果我们想要在 generate 方法中设置断点,则可以这样做:
> stop at HeatTest2:14 正在延迟断点HeatTest2:14。 将在加载类后设置。 > run 运行HeatTest2 设置未捕获的java.lang.Throwable 设置延迟的未捕获的java.lang.Throwable > VM 已启动: 设置延迟的断点HeatTest2:14 断点命中: "线程=main", HeatTest2.generate(), 行=14 bci=0 14 Test heatWay = new Test(); main[1] next > 已完成的步骤: "线程=main", HeatTest2.generate(), 行=15 bci=8 15 } main[1] next > 已完成的步骤: "线程=main", HeatTest2.main(), 行=21 bci=12 21 } main[1] next > 应用程序已退出