- 實戰Java虛擬機:JVM故障診斷與性能優化(第2版)
- 葛一鳴
- 1167字
- 2024-01-08 16:10:53
1.6 拋磚引玉:編譯和調試虛擬機
如果要對虛擬機進行深入的研究,那么編譯和調試Java虛擬機是必不可少的。為何要編譯自己的虛擬機呢?主要原因有兩點。
第一,通過自己編譯可以得到一個debug或者fastdebug版本的調試用虛擬機,調試用虛擬機可以支持更多的虛擬機參數,這些開發專用的虛擬機參數可以幫助開發人員獲得更多的虛擬機內部信息,而這些參數在正常發行版本中是無法使用的。因此考慮到本書的實用性,本書并不會過多介紹那些只在調試版本中使用的參數,但如果讀者有興趣,可以編譯自己的虛擬機,進行嘗試。
第二,使用自己編譯的調試版虛擬機可以進行虛擬機代碼的單步調試,有利于實現對虛擬機代碼的理解。由于虛擬機代碼比較復雜,僅通過代碼閱讀很難深入理解其實現機制,有時不得不依靠單步調試,而編譯后調試版本可以幫助你實現這一功能。
為編譯虛擬機,首先必須獲得虛擬機源碼,讀者可以使用下面的命令獲取JDK10的源碼。推薦讀者使用較新的版本,因為老版本的編譯腳本可能在某些平臺上存在問題。

筆者的編譯環境為Ubuntu系統,讀者可以選擇自己喜歡的Linux發行版進行編譯。編譯虛擬機之前,還必須做一些準備工作。
1.編譯前的準備工作
(1)安裝好依賴庫。在Ubuntu平臺上可以通過apt-get命令安裝,在CentOS平臺上可以通過yum命令安裝。比如,筆者在編譯前至少安裝了以下庫:

如果依賴庫安裝不全,在編譯過程中就會提示錯誤,從錯誤提示中,讀者應該可以得知缺少了哪些庫或者頭文件,進行安裝即可。當然,gcc和g++作為基本的編譯工具也是必須要安裝的。
(2)準備一個Boot JDK。Boot JDK用于OpenJDK編譯的執行。筆者在這里使用的是JDK8,也推薦讀者使用JDK8作為JDK10的Boot JDK。
2.準備編譯
準備就緒之后,就可以開始編譯了。
(1)進入解壓后的openjdk目錄:

(2)執行configure腳本配置編譯選項,筆者的配置如下:

在該腳本中,-with-debug-level=slowdebug代表要編譯debug版本JDK;-enable-dtrace代表開啟dtrace;-with-target-bits=64代表編譯64位JVM;-with-memory-size=3000代表編譯JDK的計算機至少需要3GB,根據計算機不同配置可以設置不同的值;-disable-warnings-as-errors代表忽略警告的信息;-enable-native-debug-symbols=internal代表生成symbol文件,這個便于后續的動態調試;-with-boot-jdk=/opt/jdk1.8.0_181/代表Boot JDK是JDK1.8。更多的編譯選項可以參考JDK源碼根目錄的README文件。
配置成功會顯示下面的信息:


(3)通過make images命令執行整個編譯,將會生成debug版本的虛擬機。編譯的過程可能會花費比較長的時間,一般來說,編譯一個版本可能需要15~45分鐘,視計算機性能而定。當編譯成功后,會有以下輸出:

進入build目錄,可以看到編譯的結果,下面顯示了debug版本的編譯結果:

有了debug版本的虛擬機,就可以使用gdb對虛擬機進行調試了。接下來將簡單地演示Java虛擬機的調試方法。
3.Java虛擬機的調試
筆者選用linux-x86_64-normal-server-slowdebug下的虛擬機對虛擬機的源碼進行調試。
(1)進入linux-x86_64-normal-server-slowdebug/jdk/bin目錄,用gdb啟動Java可執行程序。

(2)進入gdb命令行環境:


在main函數中打斷點:

執行run,繼續運行:

可以看到,當前程序停在了java.base/share/native/launcher/main.c文件的第97行。使用命令next(縮寫為n)進行單步調試。
至此,讀者就可以使用這套環境作為輔助,更好地深入Java虛擬機內部了。