java只所以被推廣,實際上很大原因是因為本身是跨平臺的,很大作用是因為虛擬機的關係。 一般情況下開發人員不需要關註虛擬機內部實現就可以日常開發了,但是有時候涉及到性能的時候就需要瞭解虛擬機的實現機制了。 那麼今天寫的內容更多的是關於編譯一套自己的虛擬機,為日後瞭解虛擬機底層原理鋪鋪路。 編譯虛擬機 ...
java只所以被推廣,實際上很大原因是因為本身是跨平臺的,很大作用是因為虛擬機的關係。
一般情況下開發人員不需要關註虛擬機內部實現就可以日常開發了,但是有時候涉及到性能的時候就需要瞭解虛擬機的實現機制了。
那麼今天寫的內容更多的是關於編譯一套自己的虛擬機,為日後瞭解虛擬機底層原理鋪鋪路。
編譯虛擬機可能會遇到很多坑,也很花費時間。也因大家的環境的差異,可能遇到的問題都不一致。
我只能說把自己遇到的問題都列出來,權當拋磚引玉了。
1首先我們應該下載openjdk的源碼,這個openjdk實際上是有一個版本歷史的,大家可以去瞭解一下,
然後這裡面的源碼內容和oracle jdk內容大部分都是一致的,少數內容不一樣。
我這裡下載的openjdk 源碼是openjdk-7u75-src-b13-18_dec_2014.zip,每個人的版本可能不太一樣,不過 是openjdk的源碼就行。
2除了上面的東西要準備,其實還要準備一個oracle的jdk,這個jdk我用的是jdk-6u32-linux-x64.bin。
3然後是在linux上先準備好各種依賴,這些依賴獲得方式待會兒會講,另外要講的是,我這裡的linux系統
是ubuntu的 16.04LTS 64位的,所以之前的東西也最好都準備64位的。
東西都準備好了,現在我們開乾!!!!
1如果之前你設置了java_home或者classpath環境變數,請先註釋掉。
2將openjdk-7u75-src-b13-18_dec_2014.zip解壓後得到openjdk文件夾,我們把他放到/usr下。
3執行jdk-6u32-linux-x64.bin,得到jdk1.6.0_32文件夾,我們講這個文件夾放到/usr/java下。
4輸入vim /etc/profile,在最後加入如下內容:
export LANG=C #BootStrap-JDK的安裝路徑,替換為自己bootstrap-JDK的路徑 export ALT_BOOTDIR=/usr/java/jdk1.6.0_32 #同上,我之前使用的是openjdk編譯的,後面運行hotspot時出現問題替換為oracleJDK,讀者可以直接替換為OracleJDK export ALT_JDK_IMPORT_PATH=/usr/java/jdk1.6.0_32 #規定幾個線程來執行這個腳本 export HOTSPOT_BUILD_JOBS=4 export ALT_PARALLEL_COMPILE_JOBS=4 #要編譯的內容,讀者可以根據需要自行選擇 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/openjdk/build export ALLOW_DOWNLOADS=true #這兩個環境變數需要去掉,不然會出問題 unset JAVA_HOME unset CLASSPATH make 2>&1 | tee $ALT_OUTPUTDIR/build.log
註意的是需要source /etc/profile,以更新配置。但是輸入後會馬上跑起來,但是現在是不會成功的,因為依賴那些還沒弄好。直接馬上接著按ctrl+c以暫停。
5在終端執行一些命令以安裝必要的依賴,命令如下:
sudo apt-get install build-essential gawk m4 libasound2-dev libcups2-dev libxrender-dev xorg-dev xutils-dev x11proto-print-dev binutils libmotif-common ant
有些地方還安裝了openjdk-6-jdk,其實這裡不安裝這個更好,我們用的是oracle的jdk來編譯我們的openjdk源碼,不建議用openjdk-6-jdk來編譯openjdk源碼,那也正是我build.sh腳本裡面指向的jdk地址是export ALT_BOOTDIR=/usr/java/jdk1.6.0_32的原因。
6現在我們到/usr/openjdk目錄去執行make sanity命令,檢查是否配置都沒問題了。如果沒有問題就會顯示
7萬事具備,只欠東風,輸入make,開始編譯,編譯出的東西會生成在/usr/openjdk/build目錄。
流程就是這樣的,不過期間會出現一些問題,根據他報的錯我們要修正一些錯誤,修正之後再繼續make命令接著編譯。
下麵是我遇到的一些錯誤和解決辦法。
1>
echo "*** This OS is not supported:" `uname -a`; exit 1;
openjdk/hotspot/make/linux/Makefile:240: recipe for target 'check_os_version' failed
解決:
將/openjdk/hotspot/make/linux/Makefile中的check_os_version下麵三行註釋掉
check_os_version:
#ifeq ($(DISABLE_HOTSPOT_OS_VERSION_CHECK)$(EMPTY_IF_NOT_SUPPORTED),)
# $(QUIETLY) >&2 echo "*** This OS is not supported:" `uname -a`; exit 1;
#endif
2>
undefined reference to `void G1SATBCardTableModRefBS::write_ref_array_pre_work<oopDesc*>(oopDesc**, int)'
解決:將hotspot/src/share/vm/gc_implementation/g1里的g1SATBCardTableModRefBS.cpp
template <class T> void G1SATBCardTableModRefBS::write_ref_array_pre_work(T* dst, int count) { if (!JavaThread::satb_mark_queue_set().is_active()) return; T* elem_ptr = dst; for (int i = 0; i < count; i++, elem_ptr++) { T heap_oop = oopDesc::load_heap_oop(elem_ptr); if (!oopDesc::is_null(heap_oop)) { enqueue(oopDesc::decode_heap_oop_not_null(heap_oop)); } } }內容下加上如下
//2017-10-19 Vicent_Chen added void G1SATBCardTableModRefBS::write_ref_array_pre(oop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } } void G1SATBCardTableModRefBS::write_ref_array_pre(narrowOop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } } //2017-10-19 Vicent_Chen added
將hotspot/src/share/vm/gc_implementation/g1里的g1SATBCardTableModRefBS.hpp如下部分
virtual void write_ref_array_pre(oop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } } virtual void write_ref_array_pre(narrowOop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } }
註釋掉,然後在加入virtual void write_ref_array_pre(oop* dst, int count, bool dest_uninitialized); virtual void write_ref_array_pre(narrowOop* dst, int count, bool dest_unintialized);
3>
Error: time is more than 10 years from present: 1136059200000
解決:
openjdk/jdk/src/share/classes/java/util/CurrencyData.properties文件中以下時間改成10年以內
AZ=AZM;2005-12-31-20-00-00;AZN
MZ=MZM;2006-06-30-22-00-00;MZN
RO=ROL;2005-06-30-21-00-00;RON
TR=TRL;2004-12-31-22-00-00;TRY
VE=VEB;2008-01-01-04-00-00;VEF
4>之後可能在編譯RMIServerImpl_Stub.class的時候,很可能是記憶體不夠了,因為我通過系統監視器觀察得到這段時間內記憶體在暴增,具體原因也不知道,但是我連續幾次在make命令重新來的時候,到最後一次
又成功了。所以遇到這種情況這種情況可以多次重來。最後一次記憶體就沒有暴增了。
編譯成功就是如下的樣子了:
之後在build文件夾內就能找到你編譯好的jdk。
謝謝大家,有什麼不明瞭的可以向我提問。