java只所以被推廣,實(shí)際上很大原因是因?yàn)楸旧硎强缙脚_(tái)的,很大作用是因?yàn)?a href="/article/63307.html">虛擬機(jī)的關(guān)系。
一般情況下開(kāi)發(fā)人員不需要關(guān)注虛擬機(jī)內(nèi)部實(shí)現(xiàn)就可以日常開(kāi)發(fā)了,但是有時(shí)候涉及到性能的時(shí)候就需要了解虛擬機(jī)的實(shí)現(xiàn)機(jī)制了。
那么今天寫(xiě)的內(nèi)容更多的是關(guān)于編譯一套自己的虛擬機(jī),為日后了解虛擬機(jī)底層原理鋪鋪路。
編譯虛擬機(jī)可能會(huì)遇到很多坑,也很花費(fèi)時(shí)間。也因大家的環(huán)境的差異,可能遇到的問(wèn)題都不一致。
我只能說(shuō)把自己遇到的問(wèn)題都列出來(lái),權(quán)當(dāng)拋磚引玉了。
1首先我們應(yīng)該下載openjdk的源碼,這個(gè)openjdk實(shí)際上是有一個(gè)版本歷史的,大家可以去了解一下,
然后這里面的源碼內(nèi)容和oracle jdk內(nèi)容大部分都是一致的,少數(shù)內(nèi)容不一樣。
我這里下載的openjdk 源碼是openjdk-7u75-src-b13-18_dec_2014.zip,每個(gè)人的版本可能不太一樣,不過(guò) 是openjdk的源碼就行。
2除了上面的東西要準(zhǔn)備,其實(shí)還要準(zhǔn)備一個(gè)oracle的jdk,這個(gè)jdk我用的是jdk-6u32-linux-x64.bin。
3然后是在linux上先準(zhǔn)備好各種依賴,這些依賴獲得方式待會(huì)兒會(huì)講,另外要講的是,我這里的linux系統(tǒng)
是ubuntu的 16.04lts 64位的,所以之前的東西也最好都準(zhǔn)備64位的。
東西都準(zhǔn)備好了,現(xiàn)在我們開(kāi)干!!!!
1如果之前你設(shè)置了java_home或者classpath環(huán)境變量,請(qǐng)先注釋掉。
2將openjdk-7u75-src-b13-18_dec_2014.zip解壓后得到openjdk文件夾,我們把他放到/usr下。
3執(zhí)行jdk-6u32-linux-x64.bin,得到j(luò)dk1.6.0_32文件夾,我們講這個(gè)文件夾放到/usr/java下。
4輸入vim /etc/profile,在最后加入如下內(nèi)容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
export lang=c #bootstrap-jdk的安裝路徑,替換為自己bootstrap-jdk的路徑 export alt_bootdir=/usr/java/jdk1. 6 .0_32 #同上,我之前使用的是openjdk編譯的,后面運(yùn)行hotspot時(shí)出現(xiàn)問(wèn)題替換為oraclejdk,讀者可以直接替換為oraclejdk export alt_jdk_import_path=/usr/java/jdk1. 6 .0_32 #規(guī)定幾個(gè)線程來(lái)執(zhí)行這個(gè)腳本 export hotspot_build_jobs= 4 export alt_parallel_compile_jobs= 4 #要編譯的內(nèi)容,讀者可以根據(jù)需要自行選擇 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 #編譯結(jié)果存放的路徑,建議存放在openjdk源碼中build文件夾 export alt_outputdir=/usr/openjdk/build export allow_downloads= true #這兩個(gè)環(huán)境變量需要去掉,不然會(huì)出問(wèn)題 unset java_home unset classpath make 2 >& 1 | tee $alt_outputdir/build.log |
注意的是需要source /etc/profile,以更新配置。但是輸入后會(huì)馬上跑起來(lái),但是現(xiàn)在是不會(huì)成功的,因?yàn)橐蕾嚹切┻€沒(méi)弄好。直接馬上接著按ctrl+c以暫停。
5在終端執(zhí)行一些命令以安裝必要的依賴,命令如下:
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,其實(shí)這里不安裝這個(gè)更好,我們用的是oracle的jdk來(lái)編譯我們的openjdk源碼,不建議用openjdk-6-jdk來(lái)編譯openjdk源碼,那也正是我build.sh腳本里面指向的jdk地址是export alt_bootdir=/usr/java/jdk1.6.0_32的原因。
6現(xiàn)在我們到/usr/openjdk目錄去執(zhí)行make sanity命令,檢查是否配置都沒(méi)問(wèn)題了。如果沒(méi)有問(wèn)題就會(huì)顯示
7萬(wàn)事具備,只欠東風(fēng),輸入make,開(kāi)始編譯,編譯出的東西會(huì)生成在/usr/openjdk/build目錄。
流程就是這樣的,不過(guò)期間會(huì)出現(xiàn)一些問(wèn)題,根據(jù)他報(bào)的錯(cuò)我們要修正一些錯(cuò)誤,修正之后再繼續(xù)make命令接著編譯。
下面是我遇到的一些錯(cuò)誤和解決辦法。
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)); } } }內(nèi)容下加上如下
//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文件中以下時(shí)間改成10年以內(nèi)
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的時(shí)候,很可能是內(nèi)存不夠了,因?yàn)槲彝ㄟ^(guò)系統(tǒng)監(jiān)視器觀察得到這段時(shí)間內(nèi)內(nèi)存在暴增,具體原因也不知道,但是我連續(xù)幾次在make命令重新來(lái)的時(shí)候,到最后一次
又成功了。所以遇到這種情況這種情況可以多次重來(lái)。最后一次內(nèi)存就沒(méi)有暴增了。
編譯成功就是如下的樣子了:
之后在build文件夾內(nèi)就能找到你編譯好的jdk。
謝謝大家,有什么不明了的可以向我提問(wèn)。
以上這篇基于編譯虛擬機(jī)jvm—openjdk的編譯詳解就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://www.cnblogs.com/abaoge/archive/2017/11/30/7932612.html