JVM 源碼分析(二):搭建 JDK 8 源碼調試環境(Windows 上使用 CLion)

前言

上一篇文章介紹了幾種 JVM,接下來,我將以 OpenJDK 8 中的 HotSpot VM 爲例,經過分析其源碼,探索 JVM 的實現。本篇主要記錄調試環境的搭建過程。html

因爲在 Windows 下編譯 JVM 必須使用 Visual Studio,然而本人用慣了 JetBrains 家的 CLion,不想更換 IDE,因此選擇在 Linux (CentOS7) 上編譯,在 Windows 上使用 CLion 遠程調試。java

這裏須要注意,因爲整個操做過程須要安裝不少工具,而且編譯時還將產生大量的臨時文件,所以,在開始編譯前必須確保有足夠的磁盤空間(最好大於20G)。linux

1、準備源碼

CentOS 中執行以下命令:c++

# 下載源碼包
wget https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-src-b04-14_jan_2020.zip

#
 若是沒有安裝 unzip,先安裝
yum install -y unzip

#
 解壓
unzip openjdk-8u41-src-b04-14_jan_2020.zip

2、安裝 "Bootstrap JDK"

OpenJDK 的編譯除了依賴 C/C++ 編譯器以外,還依賴一個 Java 編譯器。這是由於 OpenJDK 的不少模塊都是用 Java 寫的,編譯這部分代碼就須要用到另外一個 JDK。官方稱這個 JDK 爲 「Bootstrap JDK」, 它的版本應當低於須要編譯的目標 JDK 的版本。git

編譯 OpenJDK 8 須要使用 Update 7 或更高版本的 JDK 7 版本。參考源碼根目錄下的 「README-builds.html」 文件。github

CentOS 中執行以下命令:web

# 卸載已安裝的JDK
yum list installed | grep jdk
rpm -qa | grep jdk
yum remove -y xxxx

#
 確保卸載成功
java -version

#
 下載jdk-7u80,這裏選擇從華爲鏡像站下載
wget https://repo.huaweicloud.com/java/jdk/7u80-b15/jdk-7u80-linux-x64.tar.gz

#
 解壓到指定目錄
tar -zxf jdk-7u80-linux-x64.tar.gz -C /usr/local/java/

#
 配置環境變量
vim /etc/profile
 # 追加以下內容
    export JAVA_HOME=/usr/local/java/jdk1.7.0_80
    export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib/
    export PATH=$PATH:$JAVA_HOME/bin
source /etc/profile

#
 確保安裝成功
java -version

完成後如圖所示: bootstrap

3、配置編譯環境

CentOS 中執行以下命令:vim

# 安裝編譯所需工具
yum install -y gcc gcc-c++ make libXtst-devel libXt-devel libXrender-devel cups-devel freetype-devel alsa-lib-devel fontconfig-devel

#
 進入源碼目錄
cd openjdk/

#
 確保configure腳本擁有可執行權限
chmod +x configure

#
 執行configure腳本,看看缺乏什麼依賴項,根據錯誤提示安裝便可,而後重複執行直到提示成功
./configure --with-debug-level=slowdebug --enable-debug-symbols --disable-zip-debug-info

#
 參數說明
# --with-debug-level=slowdebug 設置編譯級別爲slowdebug,將會輸出較多的調試信息
# --enable-debug-symbols 啓用調試符號,將會生成調試信息文件
# --disable-zip-debug-info 禁用調試信息壓縮,不然,調試信息默認會被壓縮成"libjvm.diz"文件,調試時只能看到彙編代碼,不能跟進源碼

完成後如圖所示:bash

4、編譯與測試

CentOS 中執行以下命令:

# 編譯(這裏啓動6條編譯線程以加快編譯速度)
make JOBS=6

#
 測試
./build/linux-x86_64-normal-server-release/jdk/bin/java -version

#
 確保"libjvm.debuginfo"文件存在,不然調試時將不能跟進源碼
ls ./build/linux-x86_64-normal-server-release/jdk/lib/amd64/server/

若是 Linux 內核版本爲 4+,編譯時將出現 「This OS is not supported」 的報錯。解決辦法是修改源碼目錄下的 「./hotspot/make/linux/MakeFile」 文件,找到 SUPPORTED_OS_VERSION 變量定義的地方,在後面追加 「4%」,以下圖所示。

若是一切順利,將會看到如圖所示信息:

至此,咱們已經完成了 JDK 的編譯。

5、安裝 CMake 和 GDB

爲了在本地使用 CLion 進行遠程調試,須要在服務端安裝與本地版本相兼容的 CMake 和 GDB。

因爲從 yum 源安裝的版本較低,所以這裏選擇編譯安裝。

CentOS 中執行以下命令:

# 卸載已有的cmake和gdb
yum remove -y cmake gdb

#
 下載cmake3.14.5(使用華爲鏡像站)
wget https://mirrors4.tuna.tsinghua.edu.cn/pkgsrc/distfiles/cmake-3.14.5.tar.gz

#
 解壓
tar -zxf cmake-3.14.5.tar.gz

#
 進入cmake目錄,執行編譯安裝
cd cmake-3.14.5
./bootstrap && make && make install

#
 爲cmake命令建立軟連接
ln -s /usr/local/bin/cmake /usr/bin/cmake

#
 驗證是否安裝成功
cmake -version

#
 回到上一級目錄,準備安裝gdb
cd ..

#
 下載gdb8.1(使用華爲鏡像站)
wget https://mirrors4.tuna.tsinghua.edu.cn/pkgsrc/distfiles/gdb-8.1.tar.gz

#
 解壓
tar -zxf gdb-8.1.tar.gz

#
 安裝編譯所需工具
yum install -y texinfo

#
 進入gdb目錄,執行編譯安裝
cd gdb-8.1
./configure && make && make install

#
 爲gdb命令建立軟連接
ln -s /usr/local/bin/gdb /usr/bin/gdb

#
 驗證是否安裝成功
gdb -ver

5、準備遠程調試

在 CLion 中建立一個空項目,推薦 Language standard 選擇 C++11。

配置工具鏈,如圖所示。

配置 SFTP 鏈接,用於鏈接到遠程主機。

配置路徑映射,用於同步兩端的代碼。

配置排除路徑,排除本地的 cmake 輸出路徑。

將遠程主機的代碼同步到本地。在 Project 面板中點右鍵,在彈出的菜單中選擇 Deployment -> Download from,而後點擊目標 Server,等待下載。如圖所示。

同步的過程比較耗時,主要是由於 CLion 須要給每個文件創建映射關係。同步完成後的效果以下。

接下來須要在 CMakeLists.txt 文件中完成項目模型的配置。

CMakeLists.txt 中的一些基本配置能夠經過 「New CMake Project from Sources」 的方式讓 CLion 自動完成。不過 CLion 僅僅是把項目文件註冊進來,並無正確配置依賴關係和宏定義,當咱們打開代碼時會發現到處爆紅。

爲了解決這些爆紅,我花了兩個晚上,經反覆嘗試,終於獲得了一個看似使代碼再也不爆紅的 CMakeLists.txt 文件。

附上 CMakeLists.txt 文件的連接:https://github.com/zhangyongheng/jdkbuild/blob/master/openjdk8/CMakeLists.txt

項目模型配置好了以後,接下來就能夠開始遠程調試了。

6、開始遠程調試

首先在遠程主機上開啓 GDB 服務,命令以下:

# 開啓GDB服務,這裏指定端口號爲8899,後面跟上要調試的java命令
gdbserver :8899 /root/openjdk/build/linux-x86_64-normal-server-release/jdk/bin/java -version

#
 若是沒有安裝gdbserver,先安裝
yum install -y gdb-gdbserver

打開 CLion 的 "Run/Debug Configuration" 對話框,添加一個 "GDB Remote Debug",按照如圖所示進行配置。其中,"target remote args" 是遠程 GDB 服務的 IP 地址和端口號,"Path mappings" 是遠程項目根路徑與本地項目根路徑間的映射關係。

打開 "jdk/src/share/bin/java.c" 文件,找到 JavaMain() 函數,它是 Hotspot 虛擬機的執行入口,咱們能夠在這個方法內打上斷點。

點擊 "Debug" 開始調試,在 」GDB「 標籤頁中能夠查看到 GDB 日誌,咱們還能夠在這裏經過輸入 GDB 命令,以命令行的方式執行調試。

從 GDB 日誌中能夠看到, "libjvm.debuginfo" 文件的載入一般比較耗時,我這裏大約須要等待 3 分鐘,而後程序啓動後會停在斷點的位置。

在跟蹤調試以前,還須要設置 GDB 對 SIGSEGV 信號的處理方式,忽略調試時的 SIGSEGV 信號。

在 」GDB「 標籤頁下的 "(gdb)" 命令行中輸入 "handle SIGSEGV nostop noprint pass",如圖所示。

接下來就能夠繼續跟蹤調試了。

調試完成後,遠程 GDB 服務將會退出,再次調試須要從新開啓 GDB 服務。

相關文章
相關標籤/搜索