深刻理解JVM虛擬機-Ubuntu中安裝openJDK

最近利用閒暇時間看了看《深刻理解java虛擬機》來提升自身得知識儲備,再這裏準備將讀書學習到得知識和我的的心得記錄下來。首先調整好本身的心態,不要浮躁,由於編譯階段會無限踩坑。html

1.安裝VMware和Ubuntu系統

這本書得裏用得是Ubuntu系統,在這裏我爲了少踩坑放棄了以前一直使用得Centos7改成使用Ubuntu。VMware和Ubuntu系統安裝比較簡單,這裏我也是參照一篇博客安裝得,按照步驟安裝就能夠了,這裏我用的烏班圖版本爲ubuntu-14.04.6-desktop-amd64,這裏沒有使用跟本書寫着用的Ubuntu-10版本的,由於10版本的更新源實在太難找了。
VMware上安裝烏班圖系統參照此篇博客
固然,這裏面仍是略微有些坑。java

  1. 安裝好系統後只有用戶的帳號密碼設置,可是你在不少操做的時候都會顯示權限不足,這時候你須要修改root帳戶的密碼,使用命令sudo passwd(打開命令行操做界面快捷鍵爲Ctrl+Alt+T),而後輸入你要設置的root密碼就能夠了。
  2. VMware Tools安裝。烏班圖系統安裝好後你會發如今WMware的界面上顯示的窗口很是小,這時候你須要在系統上裝上WMware tools。
    點擊WMware控制檯上的虛擬機-安裝WMware Tools後,會在你的烏班圖系統中裝載,右鍵將壓縮包提取到桌面,右鍵解壓好的文件夾在終端打開,執行命令sudo ./vmware-install.pl,第一個提示輸入yes後一路回車,安裝好以後重啓就能夠了。

2.編譯openJDK

2.1 ANT等編譯工具下載

首先打開終端,輸入指令:node

#依賴腳本
sudo apt-get install build-essential gawk m4 libasound2-dev libcups2-dev libxrender-dev xorg-dev xutils-dev x11proto-print-dev binutils libmotif3 libmotif-dev libxt-dev ant libxtst-dev
#opendjdk7的依賴
sudo apt-get build-dep openjdk-7
複製代碼

這一步有可能會報錯 linux

錯誤圖片
這時須要先執行 sudo apt-get update,再執行上面的命令就能夠了。

2.2 手動下載包

  1. openjdk7的源包 下載地址,下載後進行解壓便可。
  2. oracle的jdk6的源包,因爲ubuntu系統自帶了openjdk8,而我要用oracleJDK1.7,因此須要先卸載系統自帶的openjdk,卸載以下:
若是安裝了OpenJDK,可用以下方法所有卸載:
$sudo apt-get purge openjdk*
複製代碼

卸載後去oracle官網下載jdk,我下載的是jdk7u80。下載完成後傳輸到Ubuntu中,放入事先建立好的文件夾,個人openjdk和jdk都是放在/home/java路徑下,而後進行解壓,解壓後須要配置一下jdk的環境配置。輸入sudo gedit ~/.bashrc,新增:程序員

export JAVA_HOME=/home/java/jdk1.7.0_80
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH
複製代碼

最後使配置生效:ubuntu

source ~/.bashrc
複製代碼

2.3 配置ubuntu的JDK和JRE的位置

$ sudo update-alternatives --install "/usr/bin/java" "java" "/home/java/jdk/jdk1.7.0_80/bin/java" 1
$ sudo update-alternatives --install "/usr/bin/javac" "javac" "/home/java/jdk/jdk1.7.0_80/bin/javac" 1
$ sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/home/java/jdk/jdk1.7.0_80/bin/javaws" 1
複製代碼

2.4 配置Oracle爲系統默認JDK/JRE

$ sudo update-alternatives --set java /home/java/jdk/jdk1.7.0_80/bin/java
$ sudo update-alternatives --set javac /home/java/jdk/jdk1.7.0_80/bin/javac
$ sudo update-alternatives --set javaws /home/java/jdk/jdk1.7.0_80/bin/javaws
複製代碼

3. build.sh文件的配置及編譯

再解壓好的openjdk文件夾中新建一個build.sh,將配置寫入。此處沒有采用本書的作法,但方法都同樣,只須要將配置放入/etc/profile中,而後source /etc/profile便可。瀏覽器

# 語言選項,必須設置,不然編譯好後會出現一個 HashTable 的 NPE錯
export LANG=C
 
# Bootstrap JDK 解壓路徑,必須設置
export ALT_BOOTDIR=/home/java/jdk1.7.0_80
 
# 容許自動下載
export ALLOW_DOWNLOADS=true
 
# 並行編譯線程數
export HOTSPOT_BUILD_JOBS=4
export ALT_PARALLEL_COMPILE_JOBS=4
 
# 比較本次 build 出來的映像與先前版本的差別,對咱們沒有意義
# 必須設置爲 false,不然 sanity 檢查爲報缺乏先前版本 JDK 的映像的錯誤提示
export SKIP_COMPARE_IMAGE=false
 
# 使用預編譯頭文件,不加這個編譯會變慢
export USE_PRECOMPILED_HEADER=true
 
# 要編譯的內容 這裏咱們全編譯其實只要前三個就能夠了自行註釋
export BUILD_LANGTOOLS=true
export BUILD_HOTSPOT=true
export BUILD_JDK=true
#export BUILD_JAXWS=true
#export BUILD_JAXP=true
#export BUILD_CORBA=true
 
# 要編譯的版本 
# export SKIP_DEBUG_BUILD=false
# export SKIP_FASTDEBUG_BUILD=true
# export DEBUG_NAME=debug
 
# 把它設置爲 false 能夠避開 javaws 和瀏覽器 Java 插件之類的部分的 build
BUILD_DEPLOY=false
 
# 把它設置爲 false 就不會 build 出安裝包,由於安裝包裏有奇怪的依賴
# 但即便不 build 出它也能獲得完整的 JDK 映像,因此仍是別 build
BUILD_INSTALL=false
 
# 編譯結果所存放的路徑
export ALT_OUTPUTDIR=/home/java/openjdk/build

export CFLAGS="-Wno-error"
export CXXFLAGS="-Wno-error"
 
# 這兩個環境變量必須去掉,否則會發生奇怪的事情
# Makefile 檢查到這兩個變量就會提示警告
unset JAVA_HOME
unset CLASSPATH

make 2>&1 | tee $ALT_OUTPUTDIR/build.log
複製代碼

而後賦予build.sh權限並運行,以下:bash

chmod 755 build.sh
#此命令是直接啓動程序進行編譯
./build.sh
複製代碼

4. 踩坑階段(WTFK)

好了,輕鬆愉快的閱讀和複製粘貼工做結束,下面就是最開心的踩坑階段,調整好本身的心情,打開百度和Google,準備開始一場燒腦的網絡衝浪吧。網絡

4.1 echo 「* This OS is not supported:」 uname -a; exit 1

* This OS is not supported: Linux pgc-virtual-machine 3.11.0-12-generic #19-Ubuntu SMP Wed Oct 9 16:12:00 UTC 2013 i686 i686 i686 GNU/Linux 
2.3 ERROR: echo 「* This OS is not supported:」 ‘uname -a‘; exit 1; 
複製代碼

這須要註釋掉hotspot/make/linux/Makefile裏面的checkOS。oracle

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

也能夠最好的辦法是在make參數後面添加 :
DISABLE_HOTSPOT_OS_VERSION_CHECK=OK
複製代碼

4.2 BUILD FAILED

/home/pgc/Downloads/openjdk/build/jaxws/build/xml_generated/build-drop-jaf_src.xml:96: Redirection detected from https to http. Protocol switch unsafe, not allowed. 
複製代碼

在這個build-drop-jaf_src.xml的96行中獲取包下載的地址失效或有問題,就會致使改問題發生,這時你須要把那些包本身下載,主要是jdk7-jaf-2010_08_19.zip這個包下載不了。
須要本身下載依賴的jaxp、jaf、jaxws
jaxp145_01.zip
jdk7-jaxws2_2_4-b03-2011_05_27.zip
jdk7-jaf-2010_08_19.zip
包下載好後進入openjdk目錄,建立drop文件夾,而後,把這下載到的三個包放到drop文件夾中。再執行:

export ALT_DROPS_DIR=/home/java/openjdk/openjdk/drop
複製代碼

上面的路徑須要根據本身的狀況進行修改。

4.3 .ed.hpp:36

/home/pgc/Downloads/openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp:430:0: error: 「__LEAF」 redefined [-Werror] 
#define __LEAF(result_type, header) \ 
^ 
![](https://user-gold-cdn.xitu.io/2019/3/25/169b54f02337c7c8?w=800&h=154&f=jpeg&s=23337)
In file included from /usr/include/features.h:374:0, 
複製代碼

這是cdefs.h中定義的宏「LEAF」與interfaceSupport.hpp衝突。能夠在interfaceSupport.hpp中增長一個「#undef LEAF」語句來解決衝突,interfaceSupport.hpp的文件地址在錯誤日誌中找到,或者可使用find命令來進行查找。

// LEAF routines do not lock, GC or throw exceptions
#ifdef __LEAF
#undef __LEAF
#define __LEAF(result_type, header) \
TRACE_CALL(result_type, header) \
debug_only(NoHandleMark __hm;) \
/* begin of body */
#endif 
複製代碼

4.4 error: converting ‘false’ to pointer type ‘methodOop’

修改/openjdk/hotspot/src/share/vm/oops/constantPoolOop.cpp 第272行 return false改成return (methodOop)false; 或者 return NULL。

4.5 error: converting ‘false’ to pointer type ‘Node*

修改openjdk/hotspot/src/share/vm/opto/loopnode.cpp: 第896行 return false改成return (Node*)false; 或者 return NULL;

4.6 ERROR gcc: error: unrecognized command line option ‘-mimpure-text’

這個-mimpure-text是gcc給Solaris的編譯選項,因此註釋掉或刪掉便可。 文件在./jdk/make/common/shared/Compiler-gcc.gmk

4.7 Error: time is more than 10 years from present: 1136059200000

修改CurrencyData.properties(路徑:jdk/src/share/classes/java/util/CurrencyData.properties)

修改108行
AZ=AZM;2018-12-31-20-00-00;AZN
修改381行
MZ=MZM;2018-06-30-22-00-00;MZN
修改443行
RO=ROL;20189-06-30-21-00-00;RON
修改535行
TR=TRL;2018-12-31-22-00-00;TRY
修改561行
VE=VEB;2018-01-01-04-00-00;VEF
複製代碼

上面的行數有可能有略微誤差,找到行數的附近而後根據關鍵字查找就能夠。

4.8 collect2: error: ld returned 1 exit status

make[5]: * [/home/pgc/Downloads/openjdk/build/lib/i386/libjsoundalsa.so] Error 1
make[5]: Leaving directory `/home/pgc/Downloads/openjdk/jdk/make/javax/sound/jsoundalsa’
make[4]: * [build] Error 1 
複製代碼

遇到和」javax/sound/jsoundalsa」相關的一個錯誤,須要修改openjdk/jdk/make/javax/sound/jsoundalsa目錄下的Makefile文件,找到 LDFLAGS += -lasound 修改成 OTHER_LDLIBS += -lasound

4.9 ./test_gamma錯誤

這須要去掉或者註釋掉hotspot/make/linux/Makefile 文件中全部包含test_gamma的整行!!!必定要是整行!

5 總結

以上的問題應該還不是編譯openjdk全部的坑,可能有些問題我尚未遇到,但這些坑就已經讓我搞了三天的時間才搞定,若是遇到其餘比較奇葩的坑,那隻能自行baidu和Google了,最終順利的話靜靜等待10分鐘左右(依每人各電腦性能不一樣,時間可能不同)的漫長等待,最終就編譯好了,編譯完成後會打印一下信息。


如此,就大功告成了。

6 編譯HotSpot

jdk編譯完成後須要編譯HotSpot,下面來一段HotSpot的介紹

提起HotSpot VM,相信全部Java程序員都知道,它是Sun JDK和OpenJDK中所帶的虛擬機,也是目前使用範圍最廣的Java虛擬機。
但不必定全部人都知道的是,這個目前看起來「血統純正」的虛擬機在最初並不是由Sun公司開發,而是由一家名爲「Longview Technologies」的小公司設計的;
甚至這個虛擬機最初並不是是爲Java語言而開發的,它來源於Strongtalk VM,
而這款虛擬機中至關多的技術又是來源於一款支持Self語言實現「達到C語言50%以上的執行效率」的目標而設計的虛擬機,
Sun公司注意到了這款虛擬機在JIT編譯上有許多優秀的理念和實際效果,在1997年收購了Longview Technologies公司,從而得到了HotSpot VM。

HotSpot VM既繼承了Sun以前兩款商用虛擬機的優勢(如前面提到的準確式內存管理),也有許多本身新的技術優點,
如它名稱中的HotSpot指的就是它的熱點代碼探測技術(其實兩個VM基本上是同時期的獨立產品,HotSpot還稍早一些,HotSpot一開始就是準確式GC,
而Exact VM之中也有與HotSpot幾乎同樣的熱點探測。
爲了Exact VM和HotSpot VM哪一個成爲Sun主要支持的VM產品,在Sun公司內部還有過爭論,HotSpot戰勝Exact並不能算技術上的勝利),
HotSpot VM的熱點代碼探測能力能夠經過執行計數器找出最具備編譯價值的代碼,而後通知JIT編譯器以方法爲單位進行編譯。
若是一個方法被頻繁調用,或方法中有效循環次數不少,將會分別觸發標準編譯和OSR(棧上替換)編譯動做。
經過編譯器與解釋器恰當地協同工做,能夠在最優化的程序響應時間與最佳執行性能中取得平衡,並且無須等待本地代碼輸出才能執行程序,
即時編譯的時間壓力也相對減少,這樣有助於引入更多的代碼優化技術,輸出質量更高的本地代碼。

在2006年的JavaOne大會上,Sun公司宣佈最終會把Java開源,並在隨後的一年,陸續將JDK的各個部分(其中固然也包括了HotSpot VM)在GPL協議下公開了源碼,
並在此基礎上創建了OpenJDK。這樣,HotSpot VM便成爲了Sun JDK和OpenJDK兩個實現極度接近的JDK項目的共同虛擬機。

在2008年和2009年,Oracle公司分別收購了BEA公司和Sun公司,這樣Oracle就同時擁有了兩款優秀的Java虛擬機:JRockit VM和HotSpot VM。
Oracle公司宣佈在不久的未來(大約應在發佈JDK 8的時候)會完成這兩款虛擬機的整合工做,使之優點互補。
整合的方式大體上是在HotSpot的基礎上,移植JRockit的優秀特性,譬如使用JRockit的垃圾回收器與MissionControl服務,
使用HotSpot的JIT編譯器與混合的運行時系統。
複製代碼

廢話很少少,盤他。 首先按照書上步驟是進入編譯輸出目錄,./build/j2sdk-image中,說裏面有一個gamma的運行文件,恕我眼拙,找了半天只看到了test_gamma,這是什麼鬼?閹割版?好吧,按照書上繼續來,進行env.sh的配置,但我發現env.sh裏面已經配置好了,emmmmm...........好智能,下一步把,運行./test_gamma -version,發現報錯了,果真是閹割版靠不住。通過一番百度和google以後發現,原來還要編譯HotSpot,好吧,看來我對書上講的還不是特別理解。 ####6.1 編譯 編譯HotSpot很是簡單,將剛剛建立的build.sh複製一份到/openjdk/hotspot/make中,若是是64位系統須要加上export ARCH_DATA_MODEL=64,不然回報錯,而後改一下編譯後的輸出路徑,若是都放到build中比較難找,因此我再openjdk目錄下新建了一個hotbuild目錄做爲輸出目錄,最後直接運行就能夠了。 執行成功後,修改env.sh,若是有就不用添加,沒有添加下面兩行

LD_LIBRART_PATH=.:{JAVA_HOME}/jre/lib/amd64/native_threads:%{JAVA_HOME}/jre/lib/amd64:
export LD_LIBRART_PATH
複製代碼

而後運行source ./env.sh使配置生效,最後找到正版的gamma,執行./gamma -version,正確會輸出一下日誌。

6.2 問題(OMG)

若是有人按照個人步驟作很是完美的成功了,那麼恭喜你。
在上一步./gamma -version這一步我遇到了一個問題,忘記截圖了,大體的意思就是在$JAVA_HOME/jre/lib/amd64這個裏面找不到東西(emmm...大概就是這個意思,原諒我比較low的英文水平)。這時候就須要反思一下前面的步驟,這時我忽然想起了書上的一句話,大概意思時」將/build/j2sdk-image中的文件複製到JAVA_HOME路徑下就能夠做爲完整的JDK使用「,那麼咱們前面的JAVA_HOME路徑指向的是Oracle JDK,是否是這個地方出了問題。so,我將JAVA_HOME路徑下的全部文件刪除,而後將j2sdk-image中的文件都複製過去,而後運行./gamma -version,果真就成功了。

7 安裝netBeans

搞完上面兩步,距離成功只剩一點點了,最後來下載安裝netBeans,直接官網下載就能夠,我安裝的是8.0版本的,要選擇支持C/C++開發的那個版本。 安裝成功後打開netBeans,新建項目。選擇基於現有源代碼的C/C++項目。

下一步,指定文件夾 /home/java/openjdk/hotspot,選擇定製,下一步。
選擇Makefile路徑,在hotspot/make中,下一步。

這裏須要修改構建命令(其中ALT_BOOTDIR爲你編譯後的jdk路徑):

${MAKE} -f Makefile clean jvmg ALT_BOOTDIR=/usr/lib/jvm/jdk1.7.0_80 ARCH_DATA_MODEL=64 LANG=C
複製代碼

一直下一步,而後等待build成功。成功後在項目上右鍵點擊屬性,這裏修改三個參數。
運行命令修改:

/home/java/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/gamma -XX:StopInterpreterAt=1 -version /home/java/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/Queens
複製代碼

運行目錄定位到/home/java/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg
環境修改成jvmg目錄下的env.sh中的參數 CLASS_PATH JAVA_HOME LD_LIBRART_PATH

最後就能夠進行運行調試了,啓動的main入口見圖。

相關文章
相關標籤/搜索