`
daimojingdeyu
  • 浏览: 274885 次
  • 性别: Icon_minigender_1
  • 来自: 山东
社区版块
存档分类
最新评论

java编译时生成调试信息选项详解(javac -g)

    博客分类:
  • Java
阅读更多

引子

先说一下为什么写这一篇小文章,最近不少同事是在问一个问题,为什么Ant编译出的代码在日志里的出错异常栈看不到行号信息,每次如果在定位问题,都需要用eclipse重新将相应的jar包编译一下,再放到问题环境上重现一下,这样再看日志才可以。而且使用ant生成的包就算是远程调试也不可用,断点总是打不上。

 

一般的开发都会有一套持续集成的环境,用作每日构建,用ant或是其他工具,开发人员一般用Eclipse或其他的IDE做开发,所以经常会遇见上面的问题。

 

原因

ant的javac任务里有对debug信息输出的设置,不过默认是不输出。

 

javac中设置调试信息级别的选项为-g,其详细含义如下,英文太简单,偶会详细介绍一下:

 

-g
Generate all debugging information, including local variables. By default, only line number and source file information is generated.
在Class文件中生成所有调试信息。也就是将会包含下面介绍的3类调试信息的所有。

 

-g:none
Do not generate any debugging information.
Class文件中不包含任何调试信息,这个是Ant在编译时默认使用的。

 

-g:{keyword list}
Generate only some kinds of debugging information, specified by a comma separated list of keywords. Valid keywords are:
          source
Source file debugging information
Class文件中固定长度的SourceFile属性,编译时如果选择了生成此属性,则会将它写到Class文件中。它用来提供产生Class文件的源文件名称。
如果不生成此属性,那么在调试时就会提示“Source not found.”。

有图有真像,我们用Eclipse来演示一下此调试开关的作用,帮助大家理解。
先设置一下eclipse编译时的选项,关闭Source file属性开关,编译选项的修改只针对此测试用的工程,所以在我们测试的工程右键->properties,在弹出的对话框中,按下图进行选择:
图1(给这个图命个名,后面还会用到)
 
上图中,1处表示单独调整本工程的编译选项,2处的最后一行则是是否生成Source file调试信息的开关,这里我们按上图去选中,则生成Class文件中不会有源文件的名称。
下一步,在Eclipse对应的工程中建立一个简单的Main.java用于测试,可以看出在Main.java文件中,我们还有另一个类Test,对于Test类来说,如果在生成Test.class文件没有Source file属性,那调试器就无法知道Test.class实际是对应的源文件是Main.java,那么我们把断点打在Test类的sayHello方法的第一行,调试时会发生什么?
public class Main {

	public static void main(String[] args) {
		Test t = new Test();
		t.sayHello();
	}
}


class Test
{
	public Test() {
		
	}
	
	public void sayHello()
	{
		int a = 10; // 断点将打在此行
		int b = a++;
		System.out.println("b:" + b);
		String hello = "Test say";
		hello += " hello";
		System.out.println(hello);
	}
}
 
好了,我们在Eclipse中启动调试Main.java,你将会得到下图中的信息:
是的,找不到源文件。
现在你应该已经理解这个调试选项的含义了。

          lines
Line number debugging information
将源文件中的行号信息写到Class文件中,此属性用于在Class文件中生成方法字节码流偏移量和源代码行号之间的映射关系。就像我们引子中所看到的,打印出的异常栈中看不到行号,就是因为生成Class中没有此属性导致,而远程调试时打不上断点也是这个原因。
同样的,我们在Eclipse中测试此调试选项的含义,其设置位置跟Source file属性在同一个界面,也在我们图1中设置,图1位置2的第2行,就是此选项,去选中此项,其他选项均选中,重新编译。还是用上面的Main.java来调试,看一下,会出现什么。
是的,出错了,断点无法插入成功,提示信息也很明确,让我们修改编译选项以便生成调试信息。
          
          vars
Local variable debugging information
Local variable属性建立了方法的栈帧中局部变量部分内容与源代码中局部变量名称和描述符之间的映射关系。简单一点说,如果没有此属性的信息,那我们在调试时将无法看到变量值。
我们还是在Eclipse中去掉此编译选项,不要我讲,你应该已经知道在哪里了,还是图1中的位置2,第一行就是此属性的开关,同样去选而打开其他编译开关,重新编译。再来调试一下我们的Main.java,想通过“Watch”,“Inspect”查看变量b的值,或是hello的值,你将会得到如下信息:
 
“b cannot be resolved”或是“hello cannot be resolved”。
是呀无法被解析,因为无法找到栈帧中的变量与源码中变量名之间的对应关系,无法将此运行时的信息和我们代码关联引来。

以上javac选项英文描述出自:javac - Java programming language compiler,本文只关注调试信息相关选项,其他可自行参考。

 

OK,算是介绍完了,相信大家对这几个参数的含义应该也理解了。

 

另外在最后想说一下:Eclipse编译使用编译器并不是jdk自带的javac,而是Eclipse JDT自己的编译器。虽然本文的演示是用的Eclipse,但对于javac生成类文件时的调试信息选项的含义和用法也是一样的,Eclipse的JDT编译器和javac是兼容的。

 

如果想了解Eclipes的JDT编译器和javac编译器的不同可以参考以下文档:

这里介绍了一个小例子,说明这两个编译器间的差别。

Java Compiler - Eclipse compiler vs. Sun compiler

 

这个是Eclipse的帮助里的东东,介绍Eclipse的JDT编译器的使用,(当然你可以通过本地Eclipse的帮助查看)

http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_api_compile.htm

这里面的编译方法偶在本地试过了,很好用,你也可以试式用JDT的编译器编译个文件试一试。Eclipse 3.5的示例用法如下:

D:\Program Files\eclipse\plugins>java -jar org.eclipse.jdt.core_3.5.2.v_981_R35x.jar -d F:\Study\eclipsepro\Study\src\eclipse -g F:\Study\eclipsepro\Study\src\*.java

 

还有一个参考资料就是《深入java虚拟机》,纸件的,没法贴链接了。嘿嘿

  • 大小: 56.2 KB
  • 大小: 23.4 KB
  • 大小: 15.9 KB
分享到:
评论
5 楼 shigangxing 2013-01-09  
不错不错不错
4 楼 lvjinhua 2012-06-02  
daimojingdeyu 写道
icanfly 写道
springMVC中的Annotation就大量使用了调试信息,所以如果要选用SpringMVC作为项目框架的话,编译选项中调试信息这几项就不能去掉,否则要报错。

这个是为什么?能不能详细说一下,看文档说:

引用
annotation 的retention定义了该annotation被保留的时间长短:某些annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在 class文件中;编译在class文件中的annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class 的执行,因为annotation与class在使用上是被分离的)。使用这个meta-annotation可以对annotation的“生命周期” 限制。


个人觉得如果要反射时用,是不是将Annotation只要定义成RUNTIME的就可以了?和编译选项没有关系吧?

spring在有些地方确实使用了调试信息,比如Spring MVC3中的 @RequestParam 注解,但是在没有调试信息的情况下,也是可以的,但是需要多点参数,如 @RequestParam("name1")
3 楼 allenny 2011-08-16  
偶用ant编译,参数debug="on" debuglevel="lines,vars,source" ,但是打包给其他项目用,发现异常栈无法显示行号:(Unknown Source),怎么回事
2 楼 daimojingdeyu 2010-05-31  
icanfly 写道
springMVC中的Annotation就大量使用了调试信息,所以如果要选用SpringMVC作为项目框架的话,编译选项中调试信息这几项就不能去掉,否则要报错。

这个是为什么?能不能详细说一下,看文档说:

引用
annotation 的retention定义了该annotation被保留的时间长短:某些annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在 class文件中;编译在class文件中的annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class 的执行,因为annotation与class在使用上是被分离的)。使用这个meta-annotation可以对annotation的“生命周期” 限制。


个人觉得如果要反射时用,是不是将Annotation只要定义成RUNTIME的就可以了?和编译选项没有关系吧?
1 楼 icanfly 2010-05-31  
springMVC中的Annotation就大量使用了调试信息,所以如果要选用SpringMVC作为项目框架的话,编译选项中调试信息这几项就不能去掉,否则要报错。

相关推荐

    java命令行详解

    - **作用**:生成调试信息。不指定任何参数时,默认生成所有调试信息。 - **示例**: ```shell javac -g MyClass.java ``` ##### 7. `-g:none` - **作用**:不生成任何调试信息。 - **示例**: ```shell javac...

    Unix环境上的java编译与运行.

    - **-g:{lines,vars,source}**: 选择性地生成调试信息,如行号、变量值或源代码信息,根据具体需求选择。 - **-O**: 开启优化选项,这可能会使编译后的字节码执行效率更高,但可能会影响调试或增大类文件大小。 - **...

    javac不是内部或外部命令解决

    - `-g`:生成所有调试信息。 - `-g:none`:不生成任何调试信息。 - `-g:{lines,vars,source}`:仅生成特定类型的调试信息。 - `-nowarn`:编译时不显示警告信息。 - `-verbose`:显示编译过程的详细信息。 - `-...

    java的环境安装与调试 实验报告

    - `-g`:生成所有调试信息。 - `-g:none`:不生成任何调试信息。 - `-g:{lines,vars,source}`:仅生成某些调试信息。 - `-nowarn`:不生成任何警告。 - `-verbose`:输出有关编译器正在执行的操作的消息。 - `...

    java 2语言命令详解

    - 编译选项包括:-g(添加调试信息)、-d(指定目标目录)、-cp或-classpath(设置类路径)等。 2. **java**:Java解释器 - `java`命令用于运行Java程序。例如,`java HelloWorld`将执行已编译的HelloWorld类。 ...

    JDK开发工具命令集合

    - `-g`:生成完整的调试信息。 - `-g:none`:不生成任何调试信息。 - `-g:{lines,vars,source}`:仅生成特定类型的调试信息。 - `-nowarn`:忽略警告信息。 - `-verbose`:显示详细的编译过程信息。 - `-...

    java命令详解 高手进阶

    - `-g`:生成调试信息。 **示例**: ```bash javac -d build -sourcepath src -encoding UTF-8 -deprecation -g src/com/example/MyClass.java ``` #### 3. `javaw.exe` **简介**:`javaw.exe`与`java.exe`类似...

    Java2语言命令详解

    常用的选项包括`-g`(添加调试信息)、`-classpath`(设置类路径)和`-d`(指定输出目录)。 2. **java**:Java解释器 `java`命令用于执行编译后的Java类文件。基本语法是`java [选项] 类名 [参数]`。例如,`java ...

    21天学通JAVA(高清版)

    - `-g`: 生成调试信息。 - `-g:none`: 不生成调试信息。 - `-g:{lines,vars,source}`: 只生成特定类型的调试信息。 - `-O`: 进行优化,可能会使类文件变大。 - `-nowarn`: 忽略警告。 - `-verbose`: 输出详细...

    亲测可用java-1.8.0-openjdk.linux.x86_64.zip

    开发包通常会包含JDK中的核心组件,如Java编译器(javac)、Java虚拟机(JVM)、Java运行时环境(JRE)以及开发工具,例如Javadoc(生成API文档)和JAR(打包工具)等。 在CentOS上安装这个开发包后,你可以进行...

    JDK /bin目录下常用命令详解

    JDK(Java Development Kit)是 Sun 公司的 Java 软件产品,提供了多种工具和命令来帮助开发和调试 JAVA 应用程序。所有命令都可以在 JDK 的 bin 目录下找到。每个命令都可以使用“-help”选项来查看帮助信息。下面...

    m文件编译成jar文件进行java调用归纳.pdf

    - 在开发过程中可能会遇到各种错误,如编译错误或运行时错误等,建议仔细检查错误信息,并根据Matlab官方文档进行调试。 通过上述步骤,可以有效地将Matlab的.m文件编译为jar文件,并实现在Java项目中的调用,这...

    \Java2语言命令详解(PDG).

    Java 2语言命令详解 Java 作为一门广泛使用的编程语言,其命令行工具在开发、编译、运行和管理Java程序中起着至关重要的作用。本文将深入探讨Java 2平台(J2SE)下的主要命令及其用法,帮助开发者更好地理解和掌握...

    java程序员考试题库

    ### Java程序员考试题库知识点详解 #### 一、基础知识练习概览 本章节涵盖了Java的基础知识,主要包括Java入门、数据类型和运算符等关键概念。这些知识点对于初学者来说至关重要,同时也是进阶学习的重要基石。 #...

    XJad(Java源代码反编译工具

    **XJad:Java源代码反编译工具详解** 在Java开发中,有时我们需要查看或理解已编译的.class文件中的原始源代码,但原始源代码可能丢失或未公开。这时,就需要用到反编译工具,XJad便是其中之一。XJad是一款早期的...

Global site tag (gtag.js) - Google Analytics