[讨论] 为什么有时候调试代码的时候看不到变量的值。

xgj1988 2011-04-26
现在有以下情况,我想跟一下SUN JDK的某个地方的代码想看看。但跟踪之后不能查看代码的情况。我用的是eclipse .但是有些代码又能查看到。不知道怎么回事。
下面是图。


不知道我说的这个问题和
http://hllvm.group.iteye.com/group/topic/25725

这个问题是不是有一定的关系。。希望大家帮讲解下。
RednaxelaFX 2011-04-26
哈哈,昨天我做培训的时候还说过这个…

跟另外那帖没什么关系。这个问题很简单,就是你要调试的类的Class文件里没有包含LocalVariableTable属性表。在用Java源码编译器编译Java源码得到Class文件的时候,传-g参数就会有符号信息了。
如果你遇到看不到局部变量信息的类你手上有源码的话,就加上-g再编译一遍吧
xgj1988 2011-04-26
RednaxelaFX 写道
哈哈,昨天我做培训的时候还说过这个…

跟另外那帖没什么关系。这个问题很简单,就是你要调试的类的Class文件里没有包含LocalVariableTable属性表。在用Java源码编译器编译Java源码得到Class文件的时候,传-g参数就会有符号信息了。
如果你遇到看不到局部变量信息的类你手上有源码的话,就加上-g再编译一遍吧


  eclipse 查看源代码是根据 LocalVariableTable 属性表查看的?那你的意思是我要把JDK的源代码重新编译一份啊?
xgj1988 2011-04-26
而且为什么有的源代码他有 localvariable table 信息,有的没有呢?
IcyFenix 2011-04-26
原因撒迦说了,没有生成LocalVariableTable属性。这时候jdwp能在上下文找到变量的值,可是它不认识变量的名字啊,我来做个step by step就看的很清楚了。


代码:
public class A {
	public static void foo(int a, String b, Object c) {
		System.out.println(a + b + c);
	}
}

public class B {
	public static void foo(int a, String b, Object c) {
		System.out.println(a + b + c);
	}
}

public class T {

	public static void main(String[] args) {
		A.foo(1, "2", new Object());
		B.foo(1, "2", new Object());
	}
}


编译:
D:\Test>javac -g:lines A.java
D:\Test>javac -g B.java


调试:

xgj1988 2011-04-26
IcyFenix 写道
原因撒迦说了,没有生成LocalVariableTable属性。这时候jdwp能在上下文找到变量的值,可是它不认识变量的名字啊,我来做个step by step就看的很清楚了。


代码:
public class A {
	public static void foo(int a, String b, Object c) {
		System.out.println(a + b + c);
	}
}

public class B {
	public static void foo(int a, String b, Object c) {
		System.out.println(a + b + c);
	}
}

public class T {

	public static void main(String[] args) {
		A.foo(1, "2", new Object());
		B.foo(1, "2", new Object());
	}
}


编译:
D:\Test>javac -g:lines A.java
D:\Test>javac -g B.java


调试:






我感觉有问题。下面我依次写出来:
1:你开的开发开发环境是eclipse 吗?如果是的话,你先用命令行把代码编译了,然后再拷贝到eclipse里面吗?
2:如果你是按照上面的说法做的,那么我就可以得出,eclipse默认编译项目的时候都带有-g这个参数,不然我们自己调试自己的源代码的时候也会找不到LocalVariableTable而导致不能查看。
3:如果第二条我的假设成立,那么eclipse肯定有一个全局执行java命名的配置文件,那么这个文件在哪里?如何看?
4:就是你的回答还没有帮我解决的一点问题就是,为什么同一个rt.jar有些代码调试的时候有localvariableTable,而有的没有。难道sun的伙计不是全部编译的,而是一个文件一个文件编译的?再编译的时候可能忘了用-g(当然了,也有可能,因为可能早版本的java源代码不需要编译,所以就没编译,所以就没有localvariabletable,至于新版本新加的类可能有些也有localvariabletable,有些无。我想测试一下才能下结论)
5:就是谢谢你的热心回答。
xgj1988 2011-04-26
还有一点。你的图片是怎么发出来的,我发图片是先放到blog里上传,然后再贴地址,但是看到你为了帮我解决这个问题,贴了两个图,应该不是用这么麻烦的方式吧,是不是javaeye有其他功能,可以快速贴图的。
如果你是贴图的方式和我一样。那么我真的万分感动。
IcyFenix 2011-04-26
不用javac,用ecj当然也可以,Eclipse里面也可以设置是否要生成LocalVariableTable属性,我写那2行命令行只是为了让你看清楚一些。

eclipse的设置在这里(Add variable attributes to generated class files那个复选框):


rt.jar里面是否都带有调试信息,我没有逐个类验证,不过我想当然地、不负责任地、拍个脑袋地说:应该是吧。你截图中的是equniox里面的类,不是rt.jar的。

贴图……圈子貌似是没有贴图功能,呃,是不方便。我是在博客的草稿箱放了一个稿件,专业用来上传图片的。
RednaxelaFX 2011-04-26
Sun的JDK里,product的rt.jar是只有LineNumberTable没有LocalVariableTable的。也就是说跟不加-g或者加上-g:lines一样。

圈子的帖不能直接贴图这个我也觉得很奇怪…

xgj1988 写道
2:如果你是按照上面的说法做的,那么我就可以得出,eclipse默认编译项目的时候都带有-g这个参数,不然我们自己调试自己的源代码的时候也会找不到LocalVariableTable而导致不能查看。

对的,Eclipse默认就是会让编译器带上调试信息的。配置的位置在上面IcyFenix的截图里有了。

xgj1988 写道
3:如果第二条我的假设成立,那么eclipse肯定有一个全局执行java命名的配置文件,那么这个文件在哪里?如何看?

你做了一个错误的假设:Eclipse不是用javac来编译Java源码的,而是用它自己的编译器,名字叫ECJ。同样支持-g参数。配置的位置参考上一点。

xgj1988 写道
4:就是你的回答还没有帮我解决的一点问题就是,为什么同一个rt.jar有些代码调试的时候有localvariableTable,而有的没有。

是都没有吧…
j2se/make/common/Defs.gmk
# Any debug build should include all debug info inside the classfiles
ifeq ($(VARIANT), DBG)
  DEBUG_CLASSFILES = true
endif
ifeq ($(DEBUG_CLASSFILES),true)
  JAVACFLAGS_COMMON += -g
endif

JAVACFLAGS	   = $(JAVACFLAGS_COMMON) $(OTHER_JAVACFLAGS)
JAVAC_CMD 	   = $(JAVAC) $(JIT_OPTION) $(JAVACFLAGS) $(LANGUAGE_VERSION) $(CLASS_VERSION)

在debug build里才有-g。
xgj1988 2011-04-26
你们的回答很精彩。我先一一说明一下:

1:我刚才根据LcyFenix给的图。逐步关闭上面的复选框,然后在调试确实有问题。而且如果把add line number attributes to generated class files 关闭之后,就不能下断点了(并不是不能调试,因为调试不仅仅包括下短点,个人理解根据JPDA的定义来看说的话。),所以我们的调试不会运行。

2:我把add variable attributes to generated class file 关闭之后,可以调试源代码,但是出现a can't be resolved ,注意,这里可能是我在最开始就没表述清楚,我这里说的不can't be resolved是我在eclipse里面用watch和inspect试图的时候就会can't be resolved ,但是在variables里面会显示出他的值,但是这样又有一个新问题。也就是a,b,c变量名变成了arg0,arg1,arg2这样的形式。所以可能IcyFenix也没太懂我的意思。

例子用的是IcyFenix的
public class A {   
    public static void foo(int a, String b, Object c) {   
        System.out.println(a + b + c);   
    }   
}   
  
public class B {   
    public static void foo(int a, String b, Object c) {   
        System.out.println(a + b + c);   
    }   
}   
  
public class T {   
  
    public static void main(String[] args) {   
        A.foo(1, "2", new Object());   
        B.foo(1, "2", new Object());   
    }   
}  


所以问题就是:
1:为什么variable下面可以看到a,b,c的信息,但是在watch和inspect就不行了?

2:就是RednaxelaFX给的最后的东西不太明白是什么。哈哈

引用
j2se/make/common/Defs.gmk
Makefile代码 
# Any debug build should include all debug info inside the classfiles  
ifeq ($(VARIANT), DBG)  
  DEBUG_CLASSFILES = true  
endif  
ifeq ($(DEBUG_CLASSFILES),true)  
  JAVACFLAGS_COMMON += -g  
endif  
 
JAVACFLAGS     = $(JAVACFLAGS_COMMON) $(OTHER_JAVACFLAGS)  
JAVAC_CMD      = $(JAVAC) $(JIT_OPTION) $(JAVACFLAGS) $(LANGUAGE_VERSION) $(CLASS_VERSION)
在debug build里才有-g。
Global site tag (gtag.js) - Google Analytics