Debugger Java Application
總結一些關於Java Debug的經驗,一般來說Java開發人員調試Java程式是通過IDE,比如Eclipse,以Debug方式啟動之後,可以在任意行加入斷點,待程式運行到這一行的時候會被斷點阻塞。眾所周知Java程式是以class檔案中的位元組碼方式來運行,JVM負責解讀位元組碼轉換成JVM內部指令,如果查閱JVM
Specification的文檔,即使是手工都能翻譯出每個位元組碼的含義,就像古老的彙編指令一樣,0~255每個byte代表一個指令,不同的指令又需要不同數量的參數,由此來依次讀入恰當數量的位元組碼,翻譯成真正的機器指令運行。
其實,除了程式員編寫的程式對應的位元組碼之外,class檔案中還包含有大量的調試資訊,這些資訊是用於記錄每一個JVM指令對應著怎樣的代碼,每個變數的聲明位置,以及每個函數調用、數值計算對應的原始碼中的行號……所有這些調試資訊都可以被JVM用於運行時提供反饋,對斷點和調試操作的響應。
所以,如果沒有特別的編譯指令來處理掉這些調試資訊,也沒有混淆器來混亂這些調試資訊,即使只得到了class檔案,也可以對其反編譯或者進行運行時調試。動態調試可以使用開發人員喜好的任何Editor,IDE或者JDK內建的工具。
JVM之所以會接受動態調試發出的一系列指令,是因為JVM自身就有一套完整的Debug架構,每當Java程式在JVM中運行,只要開啟了調試開關,JVM調試架構就可以正確即時的反饋調試命令。(完全不依賴於原始碼)
JVM Debug架構規範:http://download.oracle.com/javase/1.3/docs/guide/jpda/index.html
JVM主要可以提供了三種協議來支援Runtime調試:
l
JVMDI: Java Virtual Machine Debug Interface
l
JDWP: Java Debug Wire Protocol
l
JDI: Java Debug Interface
如果要開啟JVM的Debug開關,需要加入某些啟動參數,一個典型的例子是:
-Xdebug -Xrunjdwp:transport=dt_socket, server=y, address=8000
官方解釋是:Listen for a socket connection on port 8000. Suspend this VM before main class loads (suspend=y by default). Once the debugger
application connects, it can send a JDWP command to resume the VM.
更多參數說明見官方文檔:http://download.oracle.com/javase/1.3/docs/guide/jpda/conninv.html
至於調試所用的工具,我實驗了Eclipse,IntelliJ IDE
以及JDK內建的Debugger Tool: JDB
當使用Eclipse或者IntelliJ IDE這種大型的IDE時,不外乎在Debug Configuration中添加新的Remote
Java Application,設定host和port便可開始debug,使用者可以在介面上關聯Application和Source code,以便斷點更好的反饋到Source code上。
當使用JDB的時候,主要是通過命令列互動的方式,顯示起來沒有那麼給力,但是作為瞭解原理的練習方式是非常值得推薦的。進入JDK_HOME/bin目錄下,輸入jdb即可運行,一般來說提供host和port就可以串連上Local或者Remote的開啟了Debug開關的JVM,例如:
jdb –attach 192.168.1.101:8000
有時候筆者碰到一些Java程式並無Main方法,是通過JNI本地調用驅動起來的,這個時候JDB用attach參數似乎串連不上,於是採用了另外一種建立Connection的方式:
jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.1.101,port=8000
這是因為JDB串連JVM主要通過兩種方式:shared memory和sockets,暫時沒有研究者兩種方式的細節,留作將來再談起這個話題的時候分享吧!見諒~~:)