Unknown Source的出现及解决

昨天在公司写了一段代码,很简单,就是测试Thread的dumpStack方法的使用。由于Thread的dumpStack方法不是很经常使用,但它对于若是想看看谁在运行时调用方法仍是很是有帮助的。回到正题,看输出结果:
java.lang.Exception: Stack trace
 at java.lang.Thread.dumpStack(Unknown Source)
 at Common.getInfo(TestDumpStack.java:21)
 at TestDumpStack.main(TestDumpStack.java:7)
    你们能够看到在输出的第二行,显示的是at java.lang.Thread.dumpStack(Unknown Source)。为何本身写的代码就显示出了源码文件的名字及所在行数,而jdk的类库就显示出了Unknown Source?
    相信不少人在调试代码,用log工具打印堆栈异常信息,查看代码所在行的相关调试信息时,常常会遇到Unknown Source这个头痛的问题。那么这个东西到底如何而来?
    A.Unknown Source从哪来?java

     Unknown Source,顾名思义,就是未知的源文件。由于咱们最终解释运行的是class文件,因此出现这个问题的缘由很简单,就是class文件中没有源文件的 相关调试信息。那为何class文件会没有调试信息呢?答案更简单,固然是咱们在用javac命令进行编译的时候没有指定调试信息呗。由于如今不少人都 习惯用eclipse等一些现成的ide进行编写代码,因此不多人熟悉jdk本身的javac,java,jdb等一些命令的详细参数(jdk的一些命令 和eclipse自带的一些命令可能不一样)。哈哈,不过若是你常常在linux下玩java的话,命令确定会很是熟悉。那么让咱们看看javac的一些重 要参数:
    -g-Generate all debugging information, including local variables. By default, only line number and source file information is generated.在class文件中生成全部调试信息,包括局部变量的信息。默认的话,只写入源码的行号和源文件信息。
    -g:none-Do not generate any debugging information.不生成任何调试信息。
    -g:(lines,vars,source)-只生成部分调试信息(源码行号,变量,源文件信息)。那咱们在分别介绍下lines,vars,source的含义。
         lines:将源文件中的行号信息写到Class文件中,此属性用于在Class文件中生成方法字节码流偏移量和源代码行号之间的映射关系。若是咱们不指定此属性的话,咱们将在堆栈异常信息中看不到打印的行号。
         vars:Local variable属性创建了方法的栈帧中局部变量部份内容与源代码中局部变量名称和描述符之间的映射关系。有了这个属性,调试时,咱们才能够看到变量的值。
         source:编译时指定了这个属性,会把源文件的属性信息如源文件名称写入class文件。
     说了这么多,初学者可能会迷糊,为何编译要指定这些调试信息呢?哈哈,若是编译不指定这些调试信息的话,你怎么调试呢?若是你不指定行号信息的话,你在 ide中都没法插入断点。这些调试信息在咱们调试程序的时候很是重要。不过这些编译选项一般在ide中如eclipse中早已默认了。有的人可能还不相 信,打开eclipse,依次打开菜单选项:Window->Preferences->Java->Compiler,能够看到页面 的下方有一个Classfile Generation,默认是四个选项都选的。
    那这个Unknown Source究竟是编译的时候没有指定哪一项呢?通过测试,我发现是javac编译的时候没有没有指定source选项,一定出Unknown Source这个问题。
     PS1:linux下,不少人用ant进行javac任务编译,查看堆栈异常时也常常会遇到Unknown Source的问题。ant编译时,默认至关于指定-g:none,及不生成任何调试信息的。因此若是要看到日志分析中的源码和行号信息时,要更改 build.xml中的dubug属性。
    PS2:我以为看看Log4j的日志操做类源码包会对这个理解更有帮助。linux

    B.刚开始的代码引子中,为何本身写的代码会有堆栈异常的代码行数显示,而jdk的类库(rt.jar-Runtime Java Archive)代码会出现Unknown Source?
    答案很简单,由于咱们直接用的是jdk直接编译好的class文件。而rt.jar源码编译打包的时候,是没有将调试信息放入class文件的。因此才会 显示Unknown Source。其实,道理很简单,sun的类库正常的状况下确定不会有bug的,以前确定都是调试过不少遍的,因此没有必要再加入调试信息,你只负责用就 行了。因此,出现Unknown Source很正常。
     PS:其实,我以为这和软件的开发版本差很少。版本通常都有dubug版本和release版本。debug版本就是包含调试信息的。不过正式发行后,确定不包含调试信息的。由于若是包含调试信息的话,可能版本占用空间会很大,并且根本就无需调试信息。eclipse

    C.若是咱们非要对jdk的类库如rt.jar进行跟踪调试怎么办?
     由于rt.jar编译打包的时候,是不包含调试信息的。若是你只是想看看调用的过程,你只须要在eclipse中rt.jar下的Source attachment指定jdk安装目录的src.zip便可。不过若是你想跟踪jdk类库的变量值的时候,这样就不行了。除非,只有一种办法,你从新编 译一下src.zip,指定好编译参数,而后用新编译好的rt.jar覆盖掉原来的rt.jar。这样就彻底ok了。ide

    D.若是咱们想debug其余没有源代码的class文件呢?
     其实,也不难,利用jad等反编译工具编译出源码后,在进行调试。不过前提是该class文件有调试信息。工具

     PS:在网上看到了一些打印堆栈异常信息的代码,发现有的居然打印出了jdk源码的所在行数。如
at java.lang.Thread.dumpStack(Thread.java:1206)等。我以为很好奇,缘由多是从新编译了jdk的源码或者可能用的不一样的ide或者不一样版本的jdk吧。这个尚需考证。若是有懂的童鞋,能够和我交流。测试

    终于写完了。可能有不少地方须要改正,但愿不吝指教。看了看时间,是凌晨1:46分。不早了,该睡了。天亮说晚安。ui

相关文章
相关标签/搜索