Ecipse调试Java程序,查看局部变量

Eclipse默认使用的rt.jar是不带调试信息的,所以在调试时看不到局部变量。本文介绍如何实现在Ecipse调试Java程序能查看局部变量,即重新编译jdk源码包,使其带有调试信息(用-g参数),再加入到Eclipse中。

步骤1:查看javac版本

查看所使用机器的javac版本和JAVA_HOME,相关命令如下:

$ javac -version
javac 1.7.0_79

$ echo $JAVA_HOME
/usr/lib/jvm/java-7-openjdk-amd64/

#也可以在~/.profile文件查看
export JAVA_HOME="/usr/lib/jvm/java-7-openjdk-amd64/"

步骤2:下载源码文件src.zip

我机器上,/usr/lib/jvm/java-7-openjdk-amd64/src.zip是一个链接文件,链接至上一层目录的/openjdk-7/src.zip,如下:

lrwxrwxrwx 1 root root   20 oct.  22 10:07 src.zip -> ../openjdk-7/src.zip

但该文件压根就不存在,用命令sudo find / -name src.zip查找,也找不到scr.zip。自己到Java官网下载相关的jdk,解压后,即可看到src.zip。比如下载jdk7,在这里下载jdk-7u79-linux-x64.tar.gz,解压后得到jdk1.7.0_79/,在该目录下即可看到src.zip。

PS: 强烈建议下载相关的版本,我有一次不小心下成jdk8,用jdk1.7编1.8的代码,报了很多错,详情见后面。

步骤3:选择文件编译

在$JAVA_HOME 目录下创建文件夹jdk_src,将下载好的src.zip拷贝到jdk_src/,解压,命令如下:

jdk1.7.0_79$ sudo mv src.zip /usr/lib/jvm/java-7-openjdk-amd64/jdk_src/
jdk1.7.0_79$ cd /usr/lib/jvm/java-7-openjdk-amd64//jdk_src/
jdk_src$ sudo unzip src.zip 

删除文件夹com, launcher, sunw,只保留文件夹java, javax, org,否则会提示如下错误:

jdk_src/com/sun/image/codec/jpeg/JPEGCodec.java:19: error: package sun.awt.image.codec does not exist
import sun.awt.image.codec.JPEGImageDecoderImpl;
                          ^
jdk_src/com/sun/image/codec/jpeg/JPEGCodec.java:20: error: package sun.awt.image.codec does not exist
import sun.awt.image.codec.JPEGImageEncoderImpl;
                          ^

从jdk_src/目录下,选择要编译的文件,并将文件名清单存储在文件filelist.txt,命令如下:

sudo find jdk_src/ -name “*.java” > filelist.txt

在JAVA_HOME目录下创建文件夹jdc_debug,然后运行如下命令,编译jdk源码,使class文件带调试信息:

javac -sourcepath ./jdk_src/ -cp jre/lib/rt.jar -d ./jdk_debug/ -g @filelist.txt > log.txt 2>&1

# 2>&1, 1表示stdout, 2表示stderr,2>&1表示将stderr重定向到stdout, 
# 而stdout又重定向到log.txt,这样错误信息也能保存在log.txt文件里

不幸的是,提示如下错误:

jdk_src/javax/swing/MenuSelectionManager.java:66: error: cannot find symbol
                Object o = context.get(SwingUtilities2.MENU_SELECTION_MANAGER_LISTENER_KEY);
                                                      ^
  symbol:   variable MENU_SELECTION_MANAGER_LISTENER_KEY
  location: class SwingUtilities2

出乎意料的是,在整个源码包,都找不到文件SwingUtilities2.java,也找不到有定义MENU_SELECTION_MANAGER_LISTENER_KEY的地方。

我的解决办法是:先忽略这个错误,接着下面步骤,实践表明,几乎不影响调试时查看局部变量。

步骤4:打包成rt_debug.jar

进入jdc_debug,运行如下命令:

jdk_debug# jar cf0 rt_debug.jar *   //jar cf0 jar-file dir-name,  creating an uncompressed JAR file

jdk_debug# mv rt_debug.jar ../jre/lib/   //将jdc_debug移到jre/lib/目录下

步骤5:将rt_debug.jar添加到Eclipse

Window->Preferences -> Java -> Installed JREs -> 选中java-7-openjdk-amd64 -> Edit  -> Add External JARs,将rt_debug.jar加进去。

这样调试起来方便多了,今天下午用该配置好的Eclipse找到了一个很隐蔽的逻辑错误:-)

遇到问题

用jdk1.7编译1.8版本的源代码,提示如下错误:

[parsing started RegularFileObject[jdk_src/java/security/KeyStore.java]]
jdk_src/java/security/KeyStore.java:419: error: illegal start of type
        public default Set<Attribute> getAttributes() {
               ^

这是因为default关键词是jdk1.8新增的。所以源码包最好下跟jdk版本相符。

参考资料:
[1]stackoverflow: debug jdk source can’t watch variable what it is
[2]debug jdk source can’t watch variable what it is
[3]博文:解决Debug JDK source 无法查看局部变量的问题方案
[4]Recompiling the Java runtime library with debug symbols

发表评论

电子邮件地址不会被公开。 必填项已用*标注