天天看點

走進JVM,怎樣自己編譯openjdk源碼

想要深入了解JVM,就必須了解其實作機制。了解JVM實作的最好方法便是自己動手編譯JDK。好了,讓我們開始吧!

  1. 準備工作
  • 擷取OpenJDK源碼

本次編譯選擇的是OpenJDK7u,官方源碼包:https://jdk7.java.net/source.html

  • 系統需求

為了提高效率,盡量選擇Linux 或 MacOS作為編譯平台。本次使用Ubuntu12.04進行編譯。仔細閱讀源碼包中README-builds.html文檔,就可以建構編譯環境了。

  1. 配置編譯環境
  • 編譯依賴

OpenJDK包括虛拟機Hotsport | JDK API | JAXWS | JAXP等。需要各種編譯依賴,包括C++,C的編譯環境,編譯Java的JDK(稱為Bootstrap JDK),還有用于執行java代碼的Ant腳本等等。這些依賴在Linux中都可以通過指令一次安裝完成。

<pre>sudo apt-get install build-essential gawk m4 libasound2-dev libcups-dev libxrender-dev xorg-dev xutils-dev x11proto-print-dev binutils libmotif3 libmotif-dev ant</pre>           

當然,也可以在指令裡面加上openjdk-6-jdk,但是由于openjdk在後面的編譯中出現了bug,是以還是建議大家安裝Oracle jdk。注意,bootstrap JDK版本必須在6以上。

  • 環境變量

OpenJDK在編譯時會讀取許多環境變量,是以必須對Linux的環境變量進行配置。使用VIM編輯/etc/profile。 vim /etc/profile

具體在profile中添加的環境變量如下

<pre>export LANG=C

#BootStrap-JDK的安裝路徑,替換為自己bootstrap-JDK的路徑

export ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk-i386

#同上,我之前使用的是openjdk編譯的,後面運作hotspot時出現問題替換為oracleJDK,讀者可以直接替換為OracleJDK

export ALT_JDK_IMPORT_PATH=/usr/lib/jvm/java-6-openjdk-i386

#要編譯的内容,讀者可以根據需要自行選擇

export BUILD_LANGTOOLS=true #export BUILD_JAXWS=false #export BUILD_JAXP=false #export BUILD_CORBA=false export BUILD_HOTSPOT=true export BUILD_JDK=true export SKIP_COMPARE_IMAGES=true BUILD_DEPLOY=false BUILD_INSTALL=false #編譯結果存放的路徑,建議存放在openjdk源碼中build檔案夾

export ALT_OUTPUTDIR=/usr/dev/jvm/openjdk/build

export ALLOW_DOWNLOADS=true #這兩個環境變量需要去掉,不然會出問題

unset JAVA_HOME

unset CLASSPATH</pre>           

添加完成後,進入openjdk源碼路徑,通過make sanity指令來檢查設定是否正确,如果正确,會傳回Sanity check passed。

  1. 開始編譯****OpenJDK
  • 使用make指令

在openjdk目錄下,輸入make指令,正常情況下大概需要30分鐘左右,具體速度根據機器性能決定。編譯正常結束後,會出現日志清單展示内容,如圖

走進JVM,怎樣自己編譯openjdk源碼
  • 檢視編譯結果

進入build/j2sdk-image目錄下,檢視整個JDK的編譯結果,運作java –version

走進JVM,怎樣自己編譯openjdk源碼
  1. 運作****HotSpot
  • 編輯****env.sh

虛拟機的輸出結果存放在build/hotspot/outputdir/linux_i486_compiler2路徑下,如圖

走進JVM,怎樣自己編譯openjdk源碼

使用VIM編輯product目錄下的env.sh

走進JVM,怎樣自己編譯openjdk源碼

我們發現裡面已經有了JAVA_HOME CLASSPATH HOTSPOT_BUILD_USER等環境變量,我們還需要添加一個LD_LIBRARY_PATH,否則在運作時還會出現問題。

<pre>LD_LIBRARY_PATH=.:${JAVA_HOME}/jre/lib/i386/native_threads:${JAVA_HOME}/jre/lib/i386:

export LD_LIBRARY_PATH</pre>           
  • 執行指令啟動****JVM

使用如下指令,啟動虛拟機,輸出版本号

<pre>. ./env.sh ./gamma –vesion</pre>           

成功結果如圖

走進JVM,怎樣自己編譯openjdk源碼

至此成功編譯運作OpenJDK7,下面講講過程中遇到的問題。

  1. 編譯運作過程中可能會遇到的問題
  • OpenJDK6.0的****bug

使用OpenJDK6.0作為bootstrap JDK的話,在編譯及運作過程中可能會出現類似于這樣的錯誤,運作./gamma時也可能出現,這類錯誤都屬于OpenJDK-6中的bug

<pre>relocation error: /usr/lib/jvm/java-6-openjdk-i386/jre/lib/i386/libjava.so: symbol JVM_FindClassFromCaller, version SUNWprivate_1.1 not defined in file libjvm.so with link time reference</pre>           

網上提供的一種解決方案是通過find –name 'CurrencyData.properties' 找到CurrencyData檔案,把檔案中的時間全部修改為10年以内。然而我嘗試了這種方法并不能解決問題,于是嘗試把Bootstrap JDK由openjdk-6更換為OracleJDK6,終于解決問題。

  • 未取消掉JAVA_HOME變量

如果沒有在環境變量中添加unset JAVA_HOME,make Sanity時會出現以下錯誤

<pre>ERROR: Your JAVA_HOME environment variable is set. This will most likely cause the build to fail. Please unset it and start your build again.

Exiting because of the above error(s). make: *** [post-sanity] Error 1</pre>           

在/etc/profile中添加unset JAVA_HOME以解決問題

還有許多在編譯過程中遇到的問題,在前文中已經進行彌補和完善,相信大家按照這些步驟進行編譯,會省去不少麻煩。

6.總結

通過自己動手編譯OpenJDK-7的源碼,我們可以深入了解JVM的編譯環境以及運作過程。通過解決編譯過程中遇到的問題,為後續對JVM的深入探索打下了良好的基礎。在此基礎上,我們還可以通過NetBeans對Hotspot進行運作和調試,進一步了解JVM源碼的結構與細節。

繼續閱讀