前言
1991年4月,由James Gosling主導的團隊創(chuàng)造了Oak語言,java的前身,1995年5月23號,Oak語言更名Java,并且提出那句注明的:”write Once,Run Anywhere”的口號.1996年1月23日,JDK1.0發(fā)布.
當時正好趕上瀏覽器快速崛起,發(fā)展的浪潮,大家發(fā)現(xiàn)java一處編譯到處使用的特性和瀏覽器很契合,同一個頁面不可能每一個操作系統(tǒng)我都寫一遍.用現(xiàn)在的話說java正好站在這個風口上.導致它飛速發(fā)展才有了今天的江湖地位.
一蜒灰、JVM簡介
JVM是Java Virtual Machine(Java虛擬機)的縮寫弦蹂,JVM是一種用于計算設備的規(guī)范,它是一個虛構出來的計算機强窖,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的凸椿。Java虛擬機包括一套字節(jié)碼指令集、一組寄存器翅溺、一個棧脑漫、一個垃圾回收堆和一個存儲方法域。 JVM屏蔽了與具體操作系統(tǒng)平臺相關的信息咙崎,使Java程序只需生成在Java虛擬機上運行的目標代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行优幸。JVM在執(zhí)行字節(jié)碼時,實際上最終還是把字節(jié)碼解釋成具體平臺上的機器指令執(zhí)行褪猛。
Java語言的一個非常重要的特點就是與平臺的無關性网杆。而使用Java虛擬機是實現(xiàn)這一特點的關鍵。一般的高級語言如果要在不同的平臺上運行伊滋,至少需要編譯成不同的目標代碼碳却。而引入Java語言虛擬機后,Java語言在不同平臺上運行時不需要重新編譯新啼。Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息追城,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行燥撞。Java虛擬機在執(zhí)行字節(jié)碼時座柱,把字節(jié)碼解釋成具體平臺上的機器指令執(zhí)行迷帜。這就是Java的能夠“一次編譯,到處運行”的原因色洞。
二戏锹、JVM的組成
我們先把JVM這個虛擬機畫出來,如下圖所示:
從這張圖中我們可以看出火诸,JVM是運行在操作系統(tǒng)之上的锦针,它與硬件沒有直接的交互,我們再來看JVM由哪些部分組成置蜀,如下圖所示:
1奈搜、Class Loader 類加載器
類加載器的作用是加載類文件到內(nèi)存,比如編寫一個HelloWord.java 程序盯荤,然后通過javac 編譯成class 文件馋吗,那怎么才能加載到內(nèi)存中被執(zhí)行呢?Class Loader 承擔的就是這個責任秋秤,那不可能隨便建立一個.class 文件就能被加載的宏粤,Class Loader 加載的class 文件是有格式要求。
Class Loader 只管加載灼卢,只要符合文件結(jié)構就加載绍哎,至于說能不能運行,則不是它負責的鞋真,那是由Execution Engine 負責的崇堰。
2、Execution Engine 執(zhí)行引擎
執(zhí)行引擎也叫做解釋器(Interpreter) 灿巧,負責解釋命令赶袄,提交操作系統(tǒng)執(zhí)行。
3抠藕、Native Interface 本地接口
本地接口的作用是融合不同的編程語言為Java所用似舵,它的初衷是融合C/C++ 程序扰柠,Java 誕生的時候是C/C++ 橫行的時候议纯,要想立足汽烦,必須有一個聰明的积瞒、睿智的調(diào)用C/C++ 程序筷狼,于是就在內(nèi)存中專門開辟了一塊區(qū)域處理標記為native 的代碼劳吠,它的具體做法是Native Method Stack 中登記native 方法懒闷,在Execution Engine 執(zhí)行時加載native libraies 村刨。目前該方法使用的是越來越少了告抄,除非是與硬件有關的應用,比如通過Java 程序驅(qū)動打印機嵌牺,或者Java 系統(tǒng)管理生產(chǎn)設備打洼,在企業(yè)級應用中已經(jīng)比較少見龄糊,因為現(xiàn)在的異構領域間的通信很發(fā)達,比如可以使用Socket 通信募疮,也可以使用Web Service 等等炫惩,不多做介紹。
4阿浓、 Runtime data area 運行數(shù)據(jù)區(qū)
運行數(shù)據(jù)區(qū)是整個JVM 的重點。我們所有寫的程序都被加載到這里筋蓖,之后才開始運行退敦,Java 生態(tài)系統(tǒng)如此的繁榮扭勉,得益于該區(qū)域的優(yōu)良自治苛聘。
整個JVM 框架由加載器加載文件,然后執(zhí)行器在內(nèi)存中處理數(shù)據(jù)设哗,需要與異構系統(tǒng)交互是可以通過本地接口進行唱捣,瞧,一個完整的系統(tǒng)誕生了网梢!
三战虏、JVM的內(nèi)存管理
所有的數(shù)據(jù)和程序都是在運行數(shù)據(jù)區(qū)存放,它包括以下幾部分:
1巡社、 Stack 棧
棧也叫棧內(nèi)存手趣,是Java程序的運行區(qū),是在線程創(chuàng)建時創(chuàng)建朝群,它的生命期是跟隨線程的生命期姜胖,線程結(jié)束棧內(nèi)存也就釋放淀散,對于棧來說不存在垃圾回收問題蚜锨,只要線程一結(jié)束踏志,該棧就Over胀瞪。問題出來了:棧中存的是那些數(shù)據(jù)呢?又什么是格式呢凄诞?
棧中的數(shù)據(jù)都是以棧幀(Stack Frame)的格式存在,棧幀是一個內(nèi)存區(qū)塊伪朽,是一個數(shù)據(jù)集汛蝙,是一個有關方法(Method)和運行期數(shù)據(jù)的數(shù)據(jù)集窖剑,當一個方法A被調(diào)用時就產(chǎn)生了一個棧幀F(xiàn)1,并被壓入到棧中讶舰,A方法又調(diào)用了B方法需了,于是產(chǎn)生棧幀F(xiàn)2也被壓入棧肋乍,執(zhí)行完畢后,先彈出F2棧幀挪略,再彈出F1棧幀,遵循“先進后出”原則挽牢。
那棧幀中到底存在著什么數(shù)據(jù)呢禽拔?棧幀中主要保存3類數(shù)據(jù):本地變量(Local Variables)室叉,包括輸入?yún)?shù)和輸出參數(shù)以及方法內(nèi)的變量茧痕;棧操作(Operand Stack)踪旷,記錄出棧豁辉、入棧的操作徽级;棧幀數(shù)據(jù)(Frame Data),包括類文件现使、方法等等旷痕。光說比較枯燥苦蒿,我們畫個圖來理解一下Java棧,如下圖所示:
示在一個棧中有兩個棧幀,棧幀2是最先被調(diào)用的方法报强,先入棧秉溉,然后方法2又調(diào)用了方法1,棧幀1處于棧頂?shù)奈恢酶妇В瑮?處于棧底甲喝,執(zhí)行完畢后铛只,依次彈出棧幀1和棧幀2,線程結(jié)束非竿,棧釋放谋竖。
2圈盔、Heap 堆內(nèi)存
jvm中分為堆和方法區(qū),堆又進一步分為新生代和老年代铁蹈,方法區(qū)為永久代握牧。
堆中區(qū)分的新生代和老年代是為了垃圾回收娩梨,新生代中的對象存活期一般不長狈定,而老年代中的對象存活期較長,所以當垃圾回收器回收內(nèi)存時措嵌,新生代中垃圾回收效果較好企巢,會回收大量的內(nèi)存让蕾,而老年代中回收效果較差探孝,內(nèi)存回收不會太多。
基于以上特性萌抵,新生代中一般采用復制算法绍填,因為存活下來的對象是少數(shù)栖疑,所需要復制的對象少遇革,而老年代對象存活多,不適合采用復制算法锻霎,一般是標記整理和標記清除算法旋恼。
因為復制算法需要留出一塊單獨的內(nèi)存空間來以備垃圾回收時復制對象使用奄容,所以將新生代分為eden區(qū)和兩個survivor區(qū)昂勒,每次使用eden和一個survivor區(qū)戈盈,另一個survivor作為備用的對象復制內(nèi)存區(qū)。
一個JVM實例只存在一個堆類存归斤,堆內(nèi)存的大小是可以調(diào)節(jié)的官册。類加載器讀取了類文件后难捌,需要把類根吁、方法击敌、常變量放到堆內(nèi)存中,以方便執(zhí)行器執(zhí)行圣蝎,堆內(nèi)存分為三部分:
Permanent Space 永久存儲區(qū)
永久存儲區(qū)是一個常駐內(nèi)存區(qū)域徘公,用于存放JDK自身所攜帶的Class,Interface的元數(shù)據(jù),也就是說它存儲的是運行環(huán)境必須的類信息坦袍,被裝載進此區(qū)域的數(shù)據(jù)是不會被垃圾回收器回收掉的捂齐,關閉JVM才會釋放此區(qū)域所占用的內(nèi)存缩抡。
Young Generation Space 新生區(qū)
新生區(qū)是類的誕生缝其、成長内边、消亡的區(qū)域,一個類在這里產(chǎn)生嘴高,應用拴驮,最后被垃圾回收器收集柴信,結(jié)束生命随常。新生區(qū)又分為兩部分:伊甸區(qū)(Eden space)和幸存者區(qū)(Survivor pace)绪氛,所有的類都是在伊甸區(qū)被new出來的。幸存區(qū)有兩個: 0區(qū)(Survivor 0 space)和1區(qū)(Survivor 1 space)争占。當伊甸園的空間用完時臂痕,程序又需要創(chuàng)建對象刻蟹,JVM的垃圾回收器將對伊甸園區(qū)進行垃圾回收,將伊甸園區(qū)中的不再被其他對象所引用的對象進行銷毀。然后將伊甸園中的剩余對象移動到幸存0區(qū)英古。若幸存0區(qū)也滿了召调,再對該區(qū)進行垃圾回收蛮浑,然后移動到1區(qū)沮稚。那如果1區(qū)也滿了呢蕴掏?再移動到養(yǎng)老區(qū)。
Tenure generation space養(yǎng)老區(qū)
養(yǎng)老區(qū)用于保存從新生區(qū)篩選出來的JAVA對象挽荡,一般池對象都在這個區(qū)域活躍定拟。 三個區(qū)的示意圖如下:
3青自、 Method Area 方法區(qū)
方法區(qū)是被所有線程共享性穿,該區(qū)域保存所有字段和方法字節(jié)碼需曾,以及一些特殊方法如構造函數(shù),接口代碼也在此定義商源。
4牡彻、PC Register 程序計數(shù)器
每個線程都有一個程序計數(shù)器庄吼,就是一個指針严就,指向方法區(qū)中的方法字節(jié)碼梢为,由執(zhí)行引擎讀取下一條指令铸董。
四粟害、JVM垃圾回收
GC (Garbage Collection)的基本原理:將內(nèi)存中不再被使用的對象進行回收,GC中用于回收的方法稱為收集器孽文,由于GC需要消耗一些資源和時間芋哭,Java在對對象的生命周期特征進行分析后减牺,按照新生代存谎、舊生代的方式來對對象進行收集既荚,以盡可能的縮短GC對應用造成的暫停
(1)對新生代的對象的收集稱為minor GC恰聘;
(2)對舊生代的對象的收集稱為Full GC;
(3)程序中主動調(diào)用System.gc()強制執(zhí)行的GC為Full GC矾屯。
不同的對象引用類型初厚, GC會采用不同的方法進行回收产禾,JVM對象的引用分為了四種類型:
(1)強引用:默認情況下下愈,對象采用的均為強引用(這個對象的實例沒有其他對象引用势似,GC時才會被回收)
(2)軟引用:軟引用是Java中提供的一種比較適合于緩存場景的應用(只有在內(nèi)存不夠用的情況下才會被GC)
(3)弱引用:在GC時一定會被GC回收
(4)虛引用:由于虛引用只是用來得知對象是否被GC
四履因、JVM的發(fā)展
1.Sun Classic / Exact VM
以今天的視角來看栅迄,Sun Classic VM的技術可能很原始皆怕,這款虛擬機的使命也早已終結(jié)愈腾。但僅憑它“世界上第一款商用Java虛擬機”的頭銜虱黄,就足夠有讓歷史記住它的理由橱乱。
1996年1月23日泳叠,Sun公司發(fā)布JDK 1.0,Java語言首次擁有了商用的正式運行環(huán)境宗挥,這個JDK中所帶的虛擬機就是Classic VM属韧。這款虛擬機只能使用純解釋器方式來執(zhí)行Java代碼宵喂,如果要使用JIT編譯器锅棕,就必須進行外掛裸燎。但是假如外掛了JIT編譯器,JIT編譯器就完全接管了虛擬機的執(zhí)行系統(tǒng)荷荤,解釋器便不再工作了蕴纳。用戶在這款虛擬機上執(zhí)行java -version命令古毛,將會看到類似下面這行輸出:
1. java version "1.2.2"
2. Classic VM (build JDK-1.2.2-001, green threads, sunwjit)
Sun的虛擬機團隊努力去解決Classic VM所面臨的各種問題稻薇,提升運行效率塞椎。在JDK 1.2時忱屑,曾在Solaris平臺上發(fā)布過一款名為Exact VM的虛擬機莺戒,它的執(zhí)行系統(tǒng)已經(jīng)具備現(xiàn)代高性能虛擬機的雛形:如兩級即時編譯器从铲、編譯器與解釋器混合工作模式等名段。Exact VM因它使用準確式內(nèi)存管理(Exact Memory Management,也可以叫Non-Conservative/Accurate Memory Management)而得名麻惶,即虛擬機可以知道內(nèi)存中某個位置的數(shù)據(jù)具體是什么類型信夫。雖然Exact VM的技術相對Classic VM來說先進了許多静稻,但是在商業(yè)應用上只存在了很短暫的時間就被更為優(yōu)秀的HotSpot VM所取代振湾,甚至還沒有來得及發(fā)布Windows和Linux平臺下的商用版本押搪。而Classic VM的生命周期則相對長了許多大州,它在JDK 1.2之前是Sun JDK中唯一的虛擬機摧茴,在JDK 1.2時苛白,它與HotSpot VM并存焚虱,但默認使用的是Classic VM(用戶可用java-hotspot參數(shù)切換至HotSpot VM)购裙,而在JDK 1.3時,HotSpot VM成為默認虛擬機鹃栽,但Classic VM仍作為虛擬機的“備用選擇”發(fā)布(使用java-classic參數(shù)切換)躏率,直到JDK 1.4的時候,Classic VM才完全退出商用虛擬機的歷史舞臺民鼓,與Exact VM一起進入了Sun Labs Research VM之中薇芝。
**2.Sun HotSpot VM****
提起HotSpot VM,相信所有Java程序員都知道夯到,它是Sun JDK和OpenJDK中所帶的虛擬機,也是目前使用范圍最廣的Java虛擬機饮亏。但不一定所有人都知道的是耍贾,這個目前看起來“血統(tǒng)純正”的虛擬機在最初并非由Sun公司開發(fā)阅爽,而是由一家名為“Longview Technologies”的小公司設計的;甚至這個虛擬機最初并非是為Java語言而開發(fā)的荐开,它來源于Strongtalk VM付翁,而這款虛擬機中相當多的技術又是來源于一款支持Self語言實現(xiàn)“達到C語言50%以上的執(zhí)行效率”的目標而設計的虛擬機,Sun公司注意到了這款虛擬機在JIT編譯上有許多優(yōu)秀的理念和實際效果晃听,在1997年收購了Longview Technologies公司百侧,從而獲得了HotSpot VM。
HotSpot VM既繼承了Sun之前兩款商用虛擬機的優(yōu)點杂伟,也有許多自己新的技術優(yōu)勢移层,如它名稱中的HotSpot指的就是它的熱點代碼探測技術,HotSpot VM的熱點代碼探測能力可以通過執(zhí)行計數(shù)器找出最具有編譯價值的代碼赫粥,然后通知JIT編譯器以方法為單位進行編譯观话。如果一個方法被頻繁調(diào)用,或方法中有效循環(huán)次數(shù)很多越平,將會分別觸發(fā)標準編譯和OSR(棧上替換)編譯動作频蛔。通過編譯器與解釋器恰當?shù)貐f(xié)同工作,可以在最優(yōu)化的程序響應時間與最佳執(zhí)行性能中取得平衡秦叛,而且無須等待本地代碼輸出才能執(zhí)行程序晦溪,即時編譯的時間壓力也相對減小,這樣有助于引入更多的代碼優(yōu)化技術挣跋,輸出質(zhì)量更高的本地代碼三圆。
在2006年的JavaOne大會上,Sun公司宣布最終會把Java開源避咆,并在隨后的一年舟肉,陸續(xù)將JDK的各個部分(其中當然也包括了HotSpot VM)在GPL協(xié)議下公開了源碼,并在此基礎上建立了OpenJDK查库。這樣路媚,HotSpot VM便成為了Sun JDK和OpenJDK兩個實現(xiàn)極度接近的JDK項目的共同虛擬機。
在2008年和2009年樊销,Oracle公司分別收購了BEA公司和Sun公司整慎,這樣Oracle就同時擁有了兩款優(yōu)秀的Java虛擬機:JRockit VM和HotSpot VM。Oracle公司宣布在不久的將來(大約應在發(fā)布JDK 8的時候)會完成這兩款虛擬機的整合工作围苫,使之優(yōu)勢互補裤园。整合的方式大致上是在HotSpot的基礎上,移植JRockit的優(yōu)秀特性够吩,譬如使用JRockit的垃圾回收器與MissionControl服務比然,使用HotSpot的JIT編譯器與混合的運行時系統(tǒng)。
3. Sun Mobile-Embedded VM / Meta-Circular VM
Sun公司所研發(fā)的虛擬機可不僅有前面介紹的服務器周循、桌面領域的商用虛擬機强法,除此之外万俗,Sun公司面對移動和嵌入式市場,也發(fā)布過虛擬機產(chǎn)品饮怯,另外還有一類虛擬機闰歪,在設計之初就沒抱有商用的目的,僅僅是用于研究蓖墅、驗證某種技術和觀點库倘,又或者是作為一些規(guī)范的標準實現(xiàn)。這些虛擬機對于大部分不從事相關領域開發(fā)的Java程序員來說可能比較陌生论矾。Sun公司發(fā)布的其他Java虛擬機有:
(1)KVM
KVM中的K是“Kilobyte”的意思教翩,它強調(diào)簡單、輕量贪壳、高度可移植饱亿,但是運行速度比較慢。在Android闰靴、iOS等智能手機操作系統(tǒng)出現(xiàn)前曾經(jīng)在手機平臺上得到非常廣泛的應用彪笼。
(2)CDC/CLDC HotSpot Implementation
CDC/CLDC全稱是Connected(Limited)Device Configuration,在JSR-139/JSR-218規(guī)范中進行定義蚂且,它希望在手機配猫、電子書、PDA等設備上建立統(tǒng)一的Java編程接口杏死,而CDC-HI VM和CLDC-HI VM則是它們的一組參考實現(xiàn)泵肄。CDC/CLDC是整個Java ME的重要支柱,但從目前Android和iOS二分天下的移動數(shù)字設備市場看來淑翼,在這個領域中凡伊,Sun的虛擬機所面臨的局面遠不如服務器和桌面領域樂觀。
(3)Squawk VM
Squawk VM由Sun公司開發(fā)窒舟,運行于Sun SPOT(Sun Small Programmable Object Technology,一種手持的WiFi設備)诵盼,也曾經(jīng)運用于Java Card惠豺。這是一個Java代碼比重很高的嵌入式虛擬機實現(xiàn),其中諸如類加載器风宁、字節(jié)碼驗證器洁墙、垃圾收集器、解釋器戒财、編譯器和線程調(diào)度都是Java語言本身完成的热监,僅僅靠C語言來編寫設備I/O和必要的本地代碼。
(4)JavaInJava
JavaInJava是Sun公司于1997年~1998年間研發(fā)的一個實驗室性質(zhì)的虛擬機饮寞,從名字就可以看出孝扛,它試圖以Java語言來實現(xiàn)Java語言本身的運行環(huán)境列吼,既所謂的“元循環(huán)”(Meta-Circular,是指使用語言自身來實現(xiàn)其運行環(huán)境)苦始。它必須運行在另外一個宿主虛擬機之上寞钥,內(nèi)部沒有JIT編譯器,代碼只能以解釋模式執(zhí)行陌选。在20世紀末主流Java虛擬機都未能很好解決性能問題的時代理郑,開發(fā)這種項目,其執(zhí)行速度可想而知咨油。
(5)Maxine VM
Maxine VM和上面的JavaInJava非常相似您炉,它也是一個幾乎全部以Java代碼實現(xiàn)(只有用于啟動JVM的加載器使用C語言編寫)的元循環(huán)Java虛擬機。這個項目于2005年開始役电,到現(xiàn)在仍然在發(fā)展之中赚爵,比起JavaInJava,Maxine VM就顯得“靠譜”很多宴霸,它有先進的JIT編譯器和垃圾收集器(但沒有解釋器)囱晴,可在宿主模式或獨立模式下執(zhí)行,其執(zhí)行效率已經(jīng)接近了HotSpot Client VM的水平瓢谢。
4. BEA JRockit / IBM J9 VM
Oracle JRockit (原來的 Bea JRockit)系列產(chǎn)品是一個全面的運行時解決方案組合畸写,包括了行業(yè)最快的標準Java解決方案。 大量的行業(yè)[基準測試]顯示氓扛,基本JRockit JVM是世界上最快的[JVM]枯芬。JRockit面向延遲敏感型應用的解決方案JRockit Real Time提供以毫秒或微秒級的JVM響應時間,適合財務前端辦公采郎、軍事指揮與控制和電信網(wǎng)絡的需要千所。使用JRockit產(chǎn)品,客戶已經(jīng)體驗到了顯著的性能提高(一些超過了70% )和硬件成本的減少(達50%)蒜埋。
JRockit VM曾經(jīng)號稱“世界上速度最快的Java虛擬機”它是BEA公司在2002年從Appeal Virtual Machines公司收購的虛擬機淫痰。BEA公司將其發(fā)展為一款專門為服務器硬件和服務器端應用場景高度優(yōu)化的虛擬機,由于專注于服務器端應用整份,它可以不太關注程序啟動速度待错,因此JRockit內(nèi)部不包含解析器實現(xiàn),全部代碼都靠即時編譯器編譯后執(zhí)行烈评。除此之外火俄,JRockit的垃圾收集器和MissionControl服務套件等部分的實現(xiàn),在眾多Java虛擬機中也一直處于領先水平讲冠。
IBM J9 VM并不是IBM公司唯一的Java虛擬機瓜客,不過是目前其主力發(fā)展的Java虛擬機。IBM J9 VM原本是內(nèi)部開發(fā)代號,正式名稱是“IBM Technology for Java Virtual Machine”谱仪,簡稱IT4J玻熙,只是這個名字太拗口了一點,普及程度不如J9芽卿。J9 VM最初是由IBM Ottawa實驗室一個名為SmallTalk的虛擬機擴展而來的揭芍,當時這個虛擬機有一個bug是由8k值定義錯誤引起的,工程師花了很長時間終于發(fā)現(xiàn)并解決了這個錯誤卸例,此后這個版本的虛擬機就稱為K8了称杨,后來擴展出支持Java的虛擬機就被稱為J9了。與BEA JRockit專注于服務器端應用不同姑原,IBM J9的市場定位與Sun HotSpot比較接近,它是一款設計上從服務器端到桌面應用再到嵌入式都全面考慮的多用途虛擬機锭汛,J9的開發(fā)目的是作為IBM公司各種Java產(chǎn)品的執(zhí)行平臺,它的主要市場是和IBM產(chǎn)品(如IBM WebSphere等)搭配以及在IBM AIX和z/OS這些平臺上部署Java應用唤殴。
5. Azul VM / BEA Liquid VM
我們平時所提及的“高性能Java虛擬機”一般是指HotSpot到腥、JRockit、J9這類在通用平臺上運行的商用虛擬機乡范,但其實Azul VM和BEA Liquid VM這類特定硬件平臺專有的虛擬機才是“高性能”的武器。
Azul VM是Azul Systems 公司在HotSpot基礎上進行大量改進晋辆,運行于Azul Systems公司的專有硬件Vega系統(tǒng)上的Java虛擬機,每個Azul VM實例都可以管理至少數(shù)十個CPU和數(shù)百GB內(nèi)存的硬件資源芋膘,并提供在巨大內(nèi)存范圍內(nèi)實現(xiàn)可控的GC時間的垃圾收集器、為專有硬件優(yōu)化的線程調(diào)度等優(yōu)秀特性索赏。在2010年,Azul Systems公司開始從硬件轉(zhuǎn)向軟件贴彼,發(fā)布了自己的Zing JVM,可以在通用x86平臺上提供接近于Vega系統(tǒng)的特性埃儿。
Liquid VM即是現(xiàn)在的JRockit VE(Virtual Edition)器仗,它是BEA公司開發(fā)的,可以直接運行在自家Hypervisor系統(tǒng)上的JRockit VM的虛擬化版本,Liquid VM不需要操作系統(tǒng)的支持精钮,或者說它自己本身實現(xiàn)了一個專用操作系統(tǒng)的必要功能威鹿,如文件系統(tǒng)、網(wǎng)絡支持等轨香。由虛擬機越過通用操作系統(tǒng)直接控制硬件可以獲得很多好處忽你,如在線程調(diào)度時,不需要再進行內(nèi)核態(tài)/用戶態(tài)的切換等臂容,這樣可以最大限度地發(fā)揮硬件的能力科雳,提升Java程序的執(zhí)行性能。
6. Apache Harmony / Google Android Dalvik VM
Harmony VM和Dalvik VM只能稱做“虛擬機”脓杉,而不能稱做“Java虛擬機”糟秘,但是這兩款虛擬機(以及所代表的技術體系)對最近幾年的Java世界產(chǎn)生了非常大的影響和挑戰(zhàn),甚至有些悲觀的評論家認為成熟的Java生態(tài)系統(tǒng)有崩潰的可能球散。
Apache Harmony是一個Apache軟件基金會旗下以Apache License協(xié)議開源的實際兼容于JDK 1.5和JDK 1.6的Java程序運行平臺尿赚,這個介紹相當拗口。它包含自己的虛擬機和Java庫蕉堰,用戶可以在上面運行Eclipse凌净、Tomcat、Maven等常見的Java程序屋讶,但是它沒有通過TCK認證冰寻,所以我們不得不用那么一長串拗口的語言來介紹它,而不能用一句“Apache的JDK”來說明丑婿。如果一個公司要宣布自己的運行平臺“兼容于Java語言”性雄,那就必須要通過TCK(Technology Compatibility Kit)的兼容性測試。Apache基金會曾要求Sun公司提供TCK的使用授權羹奉,但是一直遭到拒絕秒旋,直到Oracle公司收購了Sun公司之后,雙方關系越鬧越僵诀拭,最終導致Apache憤然退出JCP(Java Community Process)組織,這是目前為止Java社區(qū)最嚴重的一次“分裂”细卧。
在Sun將JDK開源形成OpenJDK之后贪庙,Apache Harmony開源的優(yōu)勢被極大地削弱止邮,甚至連Harmony項目的最大參與者IBM公司也宣布辭去Harmony項目管理主席的職位,并參與OpenJDK項目的開發(fā)屈扎。雖然Harmony沒有經(jīng)過真正大規(guī)模的商業(yè)運用鹰晨,但是它的許多代碼(基本上是Java庫部分的代碼)被吸納進IBM的JDK 7實現(xiàn)及Google Android SDK之中模蜡,尤其是對Android的發(fā)展起到了很大的推動作用哩牍。
說到Android膝昆,這個時下最熱門的移動數(shù)碼設備平臺在最近幾年間的發(fā)展過程中所取得的成果已經(jīng)遠遠超越了Java ME在過去十多年所獲得的成果荚孵,Android讓Java語言真正走進了移動數(shù)碼設備領域纬朝,只是走的并非Sun公司原本想象的那一條路共苛。
Dalvik VM是Android平臺的核心組成部分之一隅茎,它的名字來源于冰島一個名為Dalvik的小漁村辟犀。Dalvik VM并不是一個Java虛擬機堂竟,它沒有遵循Java虛擬機規(guī)范出嘹,不能直接執(zhí)行Java的Class文件税稼,使用的是寄存器架構而不是JVM中常見的棧架構。但是它與Java又有著千絲萬縷的聯(lián)系闻镶,它執(zhí)行的dex(Dalvik Executable)文件可以通過Class文件轉(zhuǎn)化而來铆农,使用Java語法編寫應用程序墩剖,可以直接使用大部分的Java API等岭皂。目前Dalvik VM隨著Android一起處于迅猛發(fā)展階段爷绘,在Android 2.2中已提供即時編譯器實現(xiàn)土至,在執(zhí)行性能上有了很大的提高陶因。
7. Microsoft JVM及其他
在十幾年的Java虛擬機發(fā)展過程中楷扬,除去上面介紹的那些被大規(guī)模商業(yè)應用過的Java虛擬機外烘苹,還有許多虛擬機是不為人知的或者曾經(jīng)“絢麗”過但最終湮滅的螟加。我們以其中微軟公司的JVM為例來介紹一下捆探。
也許Java程序員聽起來可能會覺得驚訝黍图,微軟公司曾經(jīng)是Java技術的鐵桿支持者(也必須承認助被,與Sun公司爭奪Java的控制權,令Java從跨平臺技術變?yōu)榻壎ㄔ赪indows上的技術是微軟公司的主要目的)搔弄。在Java語言誕生的初期(1996年~1998年顾犹,以JDK 1.2發(fā)布為分界)炫刷,它的主要應用之一是在瀏覽器中運行Java Applets程序浑玛,微軟公司為了在IE3中支持Java Applets應用而開發(fā)了自己的Java虛擬機顾彰,雖然這款虛擬機只有Windows平臺的版本拘央,卻是當時Windows下性能最好的Java虛擬機灰伟,它在1997年和1998年連續(xù)兩年獲得了《PC Magazine》雜志的“編輯選擇獎”栏账。但好景不長挡爵,在1997年10月茶鹃,Sun公司正式以侵犯商標闭翩、不正當競爭等罪名控告微軟公司疗韵,在隨后對微軟公司的壟斷調(diào)查之中侄非,這款虛擬機也曾作為證據(jù)之一被呈送法庭。這場官司的結(jié)果是微軟公司賠償2000萬美金給Sun公司(最終微軟公司因壟斷賠償給Sun公司的總金額高達10億美元)福澡,承諾終止其Java虛擬機的發(fā)展驹马,并逐步在產(chǎn)品中移除Java虛擬機相關功能窥翩。具有諷刺意味的是寇蚊,到最后在Windows XP SP3中Java虛擬機被完全抹去的時候仗岸,Sun公司卻又到處登報希望微軟公司不要這樣做扒怖。Windows XP高級產(chǎn)品經(jīng)理Jim Cullinan稱:“我們花費了3年的時間和Sun打官司业稼,當時他們試圖阻止我們在Windows中支持Java低散,現(xiàn)在我們這樣做了熔号,可他們又在抱怨引镊,這太具有諷刺意味了》宰ィ”
我們試想一下琴拧,如果當年Sun公司沒有起訴微軟公司蚓胸,微軟公司繼續(xù)保持著對Java技術的熱情,那Java的世界會變得怎么樣呢扔枫?.NET技術是否會發(fā)展起來短荐?但歷史是沒有假設的忍宋。
五糠排、JVM相關問題
問:堆和棧有什么區(qū)別
答:堆是存放對象的入宦,但是對象內(nèi)的臨時變量是存在棧內(nèi)存中室琢,如例子中的methodVar是在運行期存放到棧中的盈滴。
棧是跟隨線程的巢钓,有線程就有棧竿报,堆是跟隨JVM的烈菌,有JVM就有堆內(nèi)存芽世。
問:堆內(nèi)存中到底存在著什么東西?
答:對象荠割,包括對象變量以及對象方法蔑鹦。
問:類變量和實例變量有什么區(qū)別?
答:靜態(tài)變量是類變量铺纽,非靜態(tài)變量是實例變量狡门,直白的說其馏,有static修飾的變量是靜態(tài)變量尝偎,沒有static修飾的變量是實例變量。靜態(tài)變量存在方法區(qū)中当辐,實例變量存在堆內(nèi)存中缘揪。
問:我聽說類變量是在JVM啟動時就初始化好的找筝,和你這說的不同呀袖裕!
答:那你是道聽途說急鳄,信我的疾宏,沒錯坎藐。
問:Java的方法(函數(shù))到底是傳值還是傳址岩馍?
答:都不是兼雄,是以傳值的方式傳遞地址赦肋,具體的說原生數(shù)據(jù)類型傳遞的值佃乘,引用類型傳遞的地址趣避。對于原始數(shù)據(jù)類型,JVM的處理方法是從Method Area或Heap中拷貝到Stack住练,然后運行frame中的方法,運行完畢后再把變量指拷貝回去盏混。
問:為什么會產(chǎn)生OutOfMemory產(chǎn)生惜论?
答:一句話:Heap內(nèi)存中沒有足夠的可用內(nèi)存了混聊。這句話要好好理解技羔,不是說Heap沒有內(nèi)存了藤滥,是說新申請內(nèi)存的對象大于Heap空閑內(nèi)存,比如現(xiàn)在Heap還空閑1M标沪,但是新申請的內(nèi)存需要1.1M金句,于是就會報OutOfMemory了违寞,可能以后的對象申請的內(nèi)存都只要0.9M军浆,于是就只出現(xiàn)一次OutOfMemory乒融,GC也正常了赞季,看起來像偶發(fā)事件怒炸,就是這么回事阿迈。 但如果此時GC沒有回收就會產(chǎn)生掛起情況畦韭,系統(tǒng)不響應了断盛。
問:我產(chǎn)生的對象不多呀罗洗,為什么還會產(chǎn)生OutOfMemory?
答:你繼承層次忒多了钢猛,Heap中 產(chǎn)生的對象是先產(chǎn)生 父類伙菜,然后才產(chǎn)生子類,明白不命迈?
問:OutOfMemory錯誤分幾種贩绕?
答:分兩種,分別是“OutOfMemoryError:java heap size”和”O(jiān)utOfMemoryError: PermGen space”,兩種都是內(nèi)存溢出,heap size是說申請不到新的內(nèi)存了治力,這個很常見覆获,檢查應用或調(diào)整堆內(nèi)存大小疑枯。
“PermGen space”是因為永久存儲區(qū)滿了具钥,這個也很常見,一般在熱發(fā)布的環(huán)境中出現(xiàn)粗恢,是因為每次發(fā)布應用系統(tǒng)都不重啟妖碉,久而久之永久存儲區(qū)中的死對象太多導致新對象無法申請內(nèi)存猛拴,一般重新啟動一下即可跛溉。
問:為什么會產(chǎn)生StackOverflowError刹勃?
答:因為一個線程把Stack內(nèi)存全部耗盡了,一般是遞歸函數(shù)造成的。
問:一個機器上可以看多個JVM嗎落萎?JVM之間可以互訪嗎兑宇?
答:可以多個JVM枚驻,只要機器承受得了梯嗽。JVM之間是不可以互訪绵估,你不能在A-JVM中訪問B-JVM的Heap內(nèi)存,這是不可能的盒使。在以前老版本的JVM中挽放,會出現(xiàn)A-JVM Crack后影響到B-JVM,現(xiàn)在版本非常少見焕襟。
問:為什么Java要采用垃圾回收機制它褪,而不采用C/C++的顯式內(nèi)存管理?
答:為了簡單块促,內(nèi)存管理不是每個程序員都能折騰好的传货。
問:為什么你沒有詳細介紹垃圾回收機制巍杈?
答:垃圾回收機制每個JVM都不同攘滩,JVM Specification只是定義了要自動釋放內(nèi)存,也就是說它只定義了垃圾回收的抽象方法逢享,具體怎么實現(xiàn)各個廠商都不同,算法各異绢彤,這東西實在沒必要深入古程。
問:JVM中到底哪些區(qū)域是共享的?哪些是私有的霜威?
答:Heap和Method Area是共享的册烈,其他都是私有的
問:什么是JIT驾中,你怎么沒說唠亚?
答:JIT是指Just In Time究珊,有的文檔把JIT作為JVM的一個部件來介紹瞬浓,有的是作為執(zhí)行引擎的一部分來介紹慰安,這都能理解。Java剛誕生的時候是一個解釋性語言聪铺,別噓化焕,即使編譯成了字節(jié)碼(byte code)也是針對JVM的,它需要再次翻譯成原生代碼(native code)才能被機器執(zhí)行铃剔,于是效率的擔憂就提出來了锣杂。Sun為了解決該問題提出了一套新的機制,好番宁,你想編譯成原生代碼元莫,沒問題,我在JVM上提供一個工具蝶押,把字節(jié)碼編譯成原生碼踱蠢,下次你來訪問的時候直接訪問原生碼就成了,于是JIT就誕生了,就這么回事茎截。
問:JVM還有哪些部分是你沒有提到的苇侵?
答:JVM是一個異常復雜的東西,寫一本磚頭書都不為過企锌,還有幾個要說明的:
常量池(constant pool):按照順序存放程序中的常量榆浓,并且進行索引編號的區(qū)域。比如int i =100撕攒,這個100就放在常量池中陡鹃。
安全管理器(Security Manager):提供Java運行期的安全控制,防止惡意攻擊抖坪,比如指定讀取文件萍鲸,寫入文件權限,網(wǎng)絡訪問擦俐,創(chuàng)建進程等等脊阴,Class Loader在Security Manager認證通過后才能加載class文件的。
方法索引表(Methods table)蚯瞧,記錄的是每個method的地址信息嘿期,Stack和Heap中的地址指針其實是指向Methods table地址。
問:為什么不建議在程序中顯式的生命System.gc()埋合?
答:因為顯式聲明是做堆內(nèi)存全掃描秽五,也就是Full GC,是需要停止所有的活動的(Stop The World Collection)饥悴,你的應用能承受這個嗎坦喘?
問:JVM有哪些調(diào)整參數(shù)?
答:非常多西设,堆內(nèi)存瓣铣、棧內(nèi)存的大小都可以定義,甚至是堆內(nèi)存的三個部分贷揽、新生代的各個比例都能調(diào)整棠笑。
六、Jvm調(diào)優(yōu)與性能優(yōu)化
在互聯(lián)網(wǎng)公司面試中禽绪,架構的底層一定是面試官會問到的問題蓖救,針對面試官一般會提到的問題,我錄制了一些底層原理的錄像視頻印屁,加扣扣群:859729143可以免費獲取這些錄像循捺,里面有些分布式,微服務雄人,性能優(yōu)化从橘,Spring,MyBatis的等源碼知識點的錄像視頻。上圖的性能優(yōu)化只是其中的一小部分恰力,這些視頻都是我找一些資深架構師朋友一起錄制出來的叉谜,視頻希望能夠幫助到以下幾類程序員:
1.對現(xiàn)在的薪資不滿,想要跳槽踩萎,卻對自己的技術沒有信心停局,不知道如何面對面試官。
2.想從傳統(tǒng)行業(yè)轉(zhuǎn)行到互聯(lián)網(wǎng)行業(yè)香府,但沒有接觸過互聯(lián)網(wǎng)技術董栽。
3.工作1 - 5年需要提升自己的核心競爭力,但學習沒有系統(tǒng)化回还,不知道自己接下來要學什么才是正確的裆泳,踩坑后又不知道找誰叹洲,百度后依然不知所以然柠硕。
4.工作5 - 10年無法突破技術瓶頸(運用過很多技術,在公司一直寫著業(yè)務代碼运提,卻依然不懂底層實現(xiàn)原理)
面試造火箭蝗柔,工作擰螺絲,希望對你有所幫助
你們的支持是我最大的動力C癖谩Q⑸ァ!栈妆!