昨天在公司寫了一段代碼,很簡單,就是測試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