今天是JVM的生日询刹,來了解下JVM的發(fā)展歷史吧

1991年4月,由James Gosling主導(dǎo)的團(tuán)隊(duì)創(chuàng)造了Oak語言,java的前身,1995年5月23號,Oak語言更名Java,并且提出那句注明的:”write Once,Run Anywhere”的口號.1996年1月23日,JDK1.0發(fā)布.

當(dāng)時正好趕上瀏覽器快速崛起,發(fā)展的浪潮,大家發(fā)現(xiàn)java一處編譯到處使用的特性和瀏覽器很契合,同一個頁面不可能每一個操作系統(tǒng)我都寫一遍.用現(xiàn)在的話說java正好站在這個風(fēng)口上.導(dǎo)致它飛速發(fā)展才有了今天的江湖地位.

今天是JVM的生日谜嫉,來了解下JVM的發(fā)展歷史吧

一、JVM簡介

JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫凹联,JVM是一種用于計(jì)算設(shè)備的規(guī)范沐兰,它是一個虛構(gòu)出來的計(jì)算機(jī),是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的蔽挠。Java虛擬機(jī)包括一套字節(jié)碼指令集住闯、一組寄存器、一個棧澳淑、一個垃圾回收堆和一個存儲方法域比原。 JVM屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息,使Java程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運(yùn)行杠巡。JVM在執(zhí)行字節(jié)碼時量窘,實(shí)際上最終還是把字節(jié)碼解釋成具體平臺上的機(jī)器指令執(zhí)行。

Java語言的一個非常重要的特點(diǎn)就是與平臺的無關(guān)性忽孽。而使用Java虛擬機(jī)是實(shí)現(xiàn)這一特點(diǎn)的關(guān)鍵绑改。一般的高級語言如果要在不同的平臺上運(yùn)行,至少需要編譯成不同的目標(biāo)代碼兄一。而引入Java語言虛擬機(jī)后厘线,Java語言在不同平臺上運(yùn)行時不需要重新編譯。Java語言使用Java虛擬機(jī)屏蔽了與具體平臺相關(guān)的信息出革,使得Java語言編譯程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼)造壮,就可以在多種平臺上不加修改地運(yùn)行。Java虛擬機(jī)在執(zhí)行字節(jié)碼時骂束,把字節(jié)碼解釋成具體平臺上的機(jī)器指令執(zhí)行耳璧。這就是Java的能夠“一次編譯,到處運(yùn)行”的原因展箱。

二旨枯、JVM的組成

我們先把JVM這個虛擬機(jī)畫出來,如下圖所示:

今天是JVM的生日混驰,來了解下JVM的發(fā)展歷史吧

從這張圖中我們可以看出攀隔,JVM是運(yùn)行在操作系統(tǒng)之上的,它與硬件沒有直接的交互栖榨,我們再來看JVM由哪些部分組成昆汹,如下圖所示:

[圖片上傳失敗...(image-6d658b-1527067349255)]

1、Class Loader 類加載器

類加載器的作用是加載類文件到內(nèi)存婴栽,比如編寫一個HelloWord.java 程序满粗,然后通過javac 編譯成class 文件,那怎么才能加載到內(nèi)存中被執(zhí)行呢愚争?Class Loader 承擔(dān)的就是這個責(zé)任映皆,那不可能隨便建立一個.class 文件就能被加載的挤聘,Class Loader 加載的class 文件是有格式要求。

Class Loader 只管加載劫扒,只要符合文件結(jié)構(gòu)就加載檬洞,至于說能不能運(yùn)行,則不是它負(fù)責(zé)的沟饥,那是由Execution Engine 負(fù)責(zé)的添怔。

2、Execution Engine 執(zhí)行引擎

執(zhí)行引擎也叫做解釋器(Interpreter) 贤旷,負(fù)責(zé)解釋命令广料,提交操作系統(tǒng)執(zhí)行。

3幼驶、Native Interface 本地接口

本地接口的作用是融合不同的編程語言為Java 所用艾杏,它的初衷是融合C/C++ 程序,Java 誕生的時候是C/C++ 橫行的時候盅藻,要想立足购桑,必須有一個聰明的、睿智的調(diào)用C/C++ 程序氏淑,于是就在內(nèi)存中專門開辟了一塊區(qū)域處理標(biāo)記為native 的代碼勃蜘,它的具體做法是Native Method Stack 中登記native 方法,在Execution Engine 執(zhí)行時加載native libraies 假残。目前該方法使用的是越來越少了缭贡,除非是與硬件有關(guān)的應(yīng)用,比如通過Java 程序驅(qū)動打印機(jī)辉懒,或者Java 系統(tǒng)管理生產(chǎn)設(shè)備阳惹,在企業(yè)級應(yīng)用中已經(jīng)比較少見,因?yàn)楝F(xiàn)在的異構(gòu)領(lǐng)域間的通信很發(fā)達(dá)眶俩,比如可以使用Socket 通信莹汤,也可以使用Web Service 等等,不多做介紹颠印。

4纲岭、 Runtime data area 運(yùn)行數(shù)據(jù)區(qū)

運(yùn)行數(shù)據(jù)區(qū)是整個JVM 的重點(diǎn)。我們所有寫的程序都被加載到這里嗽仪,之后才開始運(yùn)行荒勇,Java 生態(tài)系統(tǒng)如此的繁榮柒莉,得益于該區(qū)域的優(yōu)良自治闻坚。

整個JVM 框架由加載器加載文件,然后執(zhí)行器在內(nèi)存中處理數(shù)據(jù)兢孝,需要與異構(gòu)系統(tǒng)交互是可以通過本地接口進(jìn)行窿凤,瞧仅偎,一個完整的系統(tǒng)誕生了!

三雳殊、JVM的內(nèi)存管理

所有的數(shù)據(jù)和程序都是在運(yùn)行數(shù)據(jù)區(qū)存放橘沥,它包括以下幾部分:

1、 Stack 棧

棧也叫棧內(nèi)存夯秃,是Java程序的運(yùn)行區(qū)座咆,是在線程創(chuàng)建時創(chuàng)建,它的生命期是跟隨線程的生命期仓洼,線程結(jié)束棧內(nèi)存也就釋放介陶,對于棧來說不存在垃圾回收問題,只要線程一結(jié)束色建,該棧就Over哺呜。問題出來了:棧中存的是那些數(shù)據(jù)呢?又什么是格式呢箕戳?

棧中的數(shù)據(jù)都是以棧幀(Stack Frame)的格式存在某残,棧幀是一個內(nèi)存區(qū)塊,是一個數(shù)據(jù)集陵吸,是一個有關(guān)方法(Method)和運(yùn)行期數(shù)據(jù)的數(shù)據(jù)集玻墅,當(dāng)一個方法A被調(diào)用時就產(chǎn)生了一個棧幀F(xiàn)1,并被壓入到棧中走越,A方法又調(diào)用了B方法椭豫,于是產(chǎn)生棧幀F(xiàn)2也被壓入棧,執(zhí)行完畢后旨指,先彈出F2棧幀赏酥,再彈出F1棧幀,遵循“先進(jìn)后出”原則谆构。

那棧幀中到底存在著什么數(shù)據(jù)呢裸扶?棧幀中主要保存3類數(shù)據(jù):本地變量(Local Variables),包括輸入?yún)?shù)和輸出參數(shù)以及方法內(nèi)的變量搬素;棧操作(Operand Stack)呵晨,記錄出棧、入棧的操作熬尺;棧幀數(shù)據(jù)(Frame Data)摸屠,包括類文件、方法等等粱哼。光說比較枯燥季二,我們畫個圖來理解一下Java棧,如下圖所示:

今天是JVM的生日,來了解下JVM的發(fā)展歷史吧

示在一個棧中有兩個棧幀胯舷,棧幀2是最先被調(diào)用的方法刻蚯,先入棧,然后方法2又調(diào)用了方法1桑嘶,棧幀1處于棧頂?shù)奈恢么缎冢瑮?處于棧底,執(zhí)行完畢后逃顶,依次彈出棧幀1和棧幀2讨便,線程結(jié)束,棧釋放以政。

2器钟、Heap 堆內(nèi)存

jvm中分為堆和方法區(qū),又進(jìn)一步分為新生代和老年代妙蔗,方法區(qū)為永久代傲霸。

堆中區(qū)分的新生代和老年代是為了垃圾回收,新生代中的對象存活期一般不長眉反,而老年代中的對象存活期較長昙啄,所以當(dāng)垃圾回收器回收內(nèi)存時,新生代中垃圾回收效果較好寸五,會回收大量的內(nèi)存梳凛,而老年代中回收效果較差,內(nèi)存回收不會太多梳杏。

基于以上特性韧拒,新生代中一般采用復(fù)制算法,因?yàn)榇婊钕聛淼膶ο笫巧贁?shù)十性,所需要復(fù)制的對象少叛溢,而老年代對象存活多,不適合采用復(fù)制算法劲适,一般是標(biāo)記整理和標(biāo)記清除算法楷掉。

因?yàn)閺?fù)制算法需要留出一塊單獨(dú)的內(nèi)存空間來以備垃圾回收時復(fù)制對象使用,所以將新生代分為eden區(qū)和兩個survivor區(qū)霞势,每次使用eden和一個survivor區(qū)烹植,另一個survivor作為備用的對象復(fù)制內(nèi)存區(qū)。

一個JVM實(shí)例只存在一個堆類存愕贡,堆內(nèi)存的大小是可以調(diào)節(jié)的草雕。類加載器讀取了類文件后,需要把類固以、方法墩虹、常變量放到堆內(nèi)存中,以方便執(zhí)行器執(zhí)行,堆內(nèi)存分為三部分:

Permanent Space 永久存儲區(qū)

永久存儲區(qū)是一個常駐內(nèi)存區(qū)域败晴,用于存放JDK自身所攜帶的Class,Interface的元數(shù)據(jù),也就是說它存儲的是運(yùn)行環(huán)境必須的類信息栽渴,被裝載進(jìn)此區(qū)域的數(shù)據(jù)是不會被垃圾回收器回收掉的尖坤,關(guān)閉JVM才會釋放此區(qū)域所占用的內(nèi)存。

Young Generation Space 新生區(qū)

新生區(qū)是類的誕生闲擦、成長慢味、消亡的區(qū)域,一個類在這里產(chǎn)生墅冷,應(yīng)用纯路,最后被垃圾回收器收集,結(jié)束生命寞忿。新生區(qū)又分為兩部分:伊甸區(qū)(Eden space)和幸存者區(qū)(Survivor pace)驰唬,所有的類都是在伊甸區(qū)被new出來的。幸存區(qū)有兩個: 0區(qū)(Survivor 0 space)和1區(qū)(Survivor 1 space)腔彰。當(dāng)伊甸園的空間用完時叫编,程序又需要創(chuàng)建對象,JVM的垃圾回收器將對伊甸園區(qū)進(jìn)行垃圾回收霹抛,將伊甸園區(qū)中的不再被其他對象所引用的對象進(jìn)行銷毀搓逾。然后將伊甸園中的剩余對象移動到幸存0區(qū)。若幸存0區(qū)也滿了杯拐,再對該區(qū)進(jìn)行垃圾回收霞篡,然后移動到1區(qū)。那如果1區(qū)也滿了呢端逼?再移動到養(yǎng)老區(qū)朗兵。

Tenure generation space養(yǎng)老區(qū)

養(yǎng)老區(qū)用于保存從新生區(qū)篩選出來的JAVA對象,一般池對象都在這個區(qū)域活躍顶滩。 三個區(qū)的示意圖如下:

今天是JVM的生日矛市,來了解下JVM的發(fā)展歷史吧

3、 Method Area 方法區(qū)

方法區(qū)是被所有線程共享诲祸,該區(qū)域保存所有字段和方法字節(jié)碼浊吏,以及一些特殊方法如構(gòu)造函數(shù),接口代碼也在此定義救氯。

4找田、PC Register 程序計(jì)數(shù)器

每個線程都有一個程序計(jì)數(shù)器,就是一個指針着憨,指向方法區(qū)中的方法字節(jié)碼墩衙,由執(zhí)行引擎讀取下一條指令。

四、JVM垃圾回收

GC (Garbage Collection)的基本原理:將內(nèi)存中不再被使用的對象進(jìn)行回收漆改,GC中用于回收的方法稱為收集器心铃,由于GC需要消耗一些資源和時間,Java在對對象的生命周期特征進(jìn)行分析后挫剑,按照新生代去扣、舊生代的方式來對對象進(jìn)行收集,以盡可能的縮短GC對應(yīng)用造成的暫停

(1)對新生代的對象的收集稱為minor GC樊破;

(2)對舊生代的對象的收集稱為Full GC愉棱;

(3)程序中主動調(diào)用System.gc()強(qiáng)制執(zhí)行的GC為Full GC。

不同的對象引用類型哲戚, GC會采用不同的方法進(jìn)行回收奔滑,JVM對象的引用分為了四種類型:

(1)強(qiáng)引用:默認(rèn)情況下,對象采用的均為強(qiáng)引用(這個對象的實(shí)例沒有其他對象引用顺少,GC時才會被回收)

(2)軟引用:軟引用是Java中提供的一種比較適合于緩存場景的應(yīng)用(只有在內(nèi)存不夠用的情況下才會被GC)

(3)弱引用:在GC時一定會被GC回收

(4)虛引用:由于虛引用只是用來得知對象是否被GC

四朋其、JVM的發(fā)展

1.Sun Classic / Exact VM

以今天的視角來看,Sun Classic VM的技術(shù)可能很原始脆炎,這款虛擬機(jī)的使命也早已終結(jié)令宿。但僅憑它“世界上第一款商用Java虛擬機(jī)”的頭銜,就足夠有讓歷史記住它的理由腕窥。

1996年1月23日粒没,Sun公司發(fā)布JDK 1.0,Java語言首次擁有了商用的正式運(yùn)行環(huán)境簇爆,這個JDK中所帶的虛擬機(jī)就是Classic VM癞松。這款虛擬機(jī)只能使用純解釋器方式來執(zhí)行Java代碼,如果要使用JIT編譯器入蛆,就必須進(jìn)行外掛响蓉。但是假如外掛了JIT編譯器,JIT編譯器就完全接管了虛擬機(jī)的執(zhí)行系統(tǒng)哨毁,解釋器便不再工作了枫甲。用戶在這款虛擬機(jī)上執(zhí)行java -version命令,將會看到類似下面這行輸出:

1. java version "1.2.2"

2. Classic VM (build JDK-1.2.2-001, green threads, sunwjit)

Sun的虛擬機(jī)團(tuán)隊(duì)努力去解決Classic VM所面臨的各種問題扼褪,提升運(yùn)行效率想幻。在JDK 1.2時,曾在Solaris平臺上發(fā)布過一款名為Exact VM的虛擬機(jī)话浇,它的執(zhí)行系統(tǒng)已經(jīng)具備現(xiàn)代高性能虛擬機(jī)的雛形:如兩級即時編譯器脏毯、編譯器與解釋器混合工作模式等。Exact VM因它使用準(zhǔn)確式內(nèi)存管理(Exact Memory Management幔崖,也可以叫Non-Conservative/Accurate Memory Management)而得名食店,即虛擬機(jī)可以知道內(nèi)存中某個位置的數(shù)據(jù)具體是什么類型渣淤。雖然Exact VM的技術(shù)相對Classic VM來說先進(jìn)了許多,但是在商業(yè)應(yīng)用上只存在了很短暫的時間就被更為優(yōu)秀的HotSpot VM所取代吉嫩,甚至還沒有來得及發(fā)布Windows和Linux平臺下的商用版本价认。而Classic VM的生命周期則相對長了許多,它在JDK 1.2之前是Sun JDK中唯一的虛擬機(jī)自娩,在JDK 1.2時用踩,它與HotSpot VM并存,但默認(rèn)使用的是Classic VM(用戶可用java-hotspot參數(shù)切換至HotSpot VM)椒功,而在JDK 1.3時,HotSpot VM成為默認(rèn)虛擬機(jī)智什,但Classic VM仍作為虛擬機(jī)的“備用選擇”發(fā)布(使用java-classic參數(shù)切換)动漾,直到JDK 1.4的時候,Classic VM才完全退出商用虛擬機(jī)的歷史舞臺荠锭,與Exact VM一起進(jìn)入了Sun Labs Research VM之中旱眯。

**2.Sun HotSpot VM****

提起HotSpot VM,相信所有Java程序員都知道证九,它是Sun JDK和OpenJDK中所帶的虛擬機(jī)删豺,也是目前使用范圍最廣的Java虛擬機(jī)。但不一定所有人都知道的是愧怜,這個目前看起來“血統(tǒng)純正”的虛擬機(jī)在最初并非由Sun公司開發(fā)呀页,而是由一家名為“Longview Technologies”的小公司設(shè)計(jì)的;甚至這個虛擬機(jī)最初并非是為Java語言而開發(fā)的拥坛,它來源于Strongtalk VM蓬蝶,而這款虛擬機(jī)中相當(dāng)多的技術(shù)又是來源于一款支持Self語言實(shí)現(xiàn)“達(dá)到C語言50%以上的執(zhí)行效率”的目標(biāo)而設(shè)計(jì)的虛擬機(jī),Sun公司注意到了這款虛擬機(jī)在JIT編譯上有許多優(yōu)秀的理念和實(shí)際效果猜惋,在1997年收購了Longview Technologies公司丸氛,從而獲得了HotSpot VM。

HotSpot VM既繼承了Sun之前兩款商用虛擬機(jī)的優(yōu)點(diǎn)著摔,也有許多自己新的技術(shù)優(yōu)勢缓窜,如它名稱中的HotSpot指的就是它的熱點(diǎn)代碼探測技術(shù),HotSpot VM的熱點(diǎn)代碼探測能力可以通過執(zhí)行計(jì)數(shù)器找出最具有編譯價值的代碼谍咆,然后通知JIT編譯器以方法為單位進(jìn)行編譯禾锤。如果一個方法被頻繁調(diào)用,或方法中有效循環(huán)次數(shù)很多摹察,將會分別觸發(fā)標(biāo)準(zhǔn)編譯和OSR(棧上替換)編譯動作时肿。通過編譯器與解釋器恰當(dāng)?shù)貐f(xié)同工作,可以在最優(yōu)化的程序響應(yīng)時間與最佳執(zhí)行性能中取得平衡港粱,而且無須等待本地代碼輸出才能執(zhí)行程序螃成,即時編譯的時間壓力也相對減小旦签,這樣有助于引入更多的代碼優(yōu)化技術(shù),輸出質(zhì)量更高的本地代碼寸宏。

在2006年的JavaOne大會上宁炫,Sun公司宣布最終會把Java開源,并在隨后的一年氮凝,陸續(xù)將JDK的各個部分(其中當(dāng)然也包括了HotSpot VM)在GPL協(xié)議下公開了源碼羔巢,并在此基礎(chǔ)上建立了OpenJDK。這樣罩阵,HotSpot VM便成為了Sun JDK和OpenJDK兩個實(shí)現(xiàn)極度接近的JDK項(xiàng)目的共同虛擬機(jī)竿秆。

在2008年和2009年,Oracle公司分別收購了BEA公司和Sun公司稿壁,這樣Oracle就同時擁有了兩款優(yōu)秀的Java虛擬機(jī):JRockit VM和HotSpot VM幽钢。Oracle公司宣布在不久的將來(大約應(yīng)在發(fā)布JDK 8的時候)會完成這兩款虛擬機(jī)的整合工作,使之優(yōu)勢互補(bǔ)傅是。整合的方式大致上是在HotSpot的基礎(chǔ)上匪燕,移植JRockit的優(yōu)秀特性,譬如使用JRockit的垃圾回收器與MissionControl服務(wù)喧笔,使用HotSpot的JIT編譯器與混合的運(yùn)行時系統(tǒng)帽驯。

3. Sun Mobile-Embedded VM / Meta-Circular VM

Sun公司所研發(fā)的虛擬機(jī)可不僅有前面介紹的服務(wù)器、桌面領(lǐng)域的商用虛擬機(jī)书闸,除此之外尼变,Sun公司面對移動和嵌入式市場,也發(fā)布過虛擬機(jī)產(chǎn)品浆劲,另外還有一類虛擬機(jī)享甸,在設(shè)計(jì)之初就沒抱有商用的目的,僅僅是用于研究梳侨、驗(yàn)證某種技術(shù)和觀點(diǎn)蛉威,又或者是作為一些規(guī)范的標(biāo)準(zhǔn)實(shí)現(xiàn)。這些虛擬機(jī)對于大部分不從事相關(guān)領(lǐng)域開發(fā)的Java程序員來說可能比較陌生走哺。Sun公司發(fā)布的其他Java虛擬機(jī)有:

(1)KVM

KVM中的K是“Kilobyte”的意思蚯嫌,它強(qiáng)調(diào)簡單、輕量丙躏、高度可移植择示,但是運(yùn)行速度比較慢。在Android晒旅、iOS等智能手機(jī)操作系統(tǒng)出現(xiàn)前曾經(jīng)在手機(jī)平臺上得到非常廣泛的應(yīng)用栅盲。

(2)CDC/CLDC HotSpot Implementation

CDC/CLDC全稱是Connected(Limited)Device Configuration,在JSR-139/JSR-218規(guī)范中進(jìn)行定義废恋,它希望在手機(jī)谈秫、電子書扒寄、PDA等設(shè)備上建立統(tǒng)一的Java編程接口,而CDC-HI VM和CLDC-HI VM則是它們的一組參考實(shí)現(xiàn)拟烫。CDC/CLDC是整個Java ME的重要支柱该编,但從目前Android和iOS二分天下的移動數(shù)字設(shè)備市場看來,在這個領(lǐng)域中硕淑,Sun的虛擬機(jī)所面臨的局面遠(yuǎn)不如服務(wù)器和桌面領(lǐng)域樂觀课竣。

(3)Squawk VM

Squawk VM由Sun公司開發(fā),運(yùn)行于Sun SPOT(Sun Small Programmable Object Technology置媳,一種手持的WiFi設(shè)備)于樟,也曾經(jīng)運(yùn)用于Java Card。這是一個Java代碼比重很高的嵌入式虛擬機(jī)實(shí)現(xiàn)拇囊,其中諸如類加載器迂曲、字節(jié)碼驗(yàn)證器、垃圾收集器寂拆、解釋器奢米、編譯器和線程調(diào)度都是Java語言本身完成的抓韩,僅僅靠C語言來編寫設(shè)備I/O和必要的本地代碼纠永。

(4)JavaInJava

JavaInJava是Sun公司于1997年~1998年間研發(fā)的一個實(shí)驗(yàn)室性質(zhì)的虛擬機(jī),從名字就可以看出谒拴,它試圖以Java語言來實(shí)現(xiàn)Java語言本身的運(yùn)行環(huán)境尝江,既所謂的“元循環(huán)”(Meta-Circular,是指使用語言自身來實(shí)現(xiàn)其運(yùn)行環(huán)境)英上。它必須運(yùn)行在另外一個宿主虛擬機(jī)之上炭序,內(nèi)部沒有JIT編譯器,代碼只能以解釋模式執(zhí)行苍日。在20世紀(jì)末主流Java虛擬機(jī)都未能很好解決性能問題的時代惭聂,開發(fā)這種項(xiàng)目,其執(zhí)行速度可想而知相恃。

(5)Maxine VM

Maxine VM和上面的JavaInJava非常相似辜纲,它也是一個幾乎全部以Java代碼實(shí)現(xiàn)(只有用于啟動JVM的加載器使用C語言編寫)的元循環(huán)Java虛擬機(jī)。這個項(xiàng)目于2005年開始拦耐,到現(xiàn)在仍然在發(fā)展之中耕腾,比起JavaInJava,Maxine VM就顯得“靠譜”很多杀糯,它有先進(jìn)的JIT編譯器和垃圾收集器(但沒有解釋器)扫俺,可在宿主模式或獨(dú)立模式下執(zhí)行,其執(zhí)行效率已經(jīng)接近了HotSpot Client VM的水平固翰。

4. BEA JRockit / IBM J9 VM

Oracle JRockit (原來的 Bea JRockit)系列產(chǎn)品是一個全面的運(yùn)行時解決方案組合狼纬,包括了行業(yè)最快的標(biāo)準(zhǔn)Java解決方案羹呵。 大量的行業(yè)[基準(zhǔn)測試]顯示,基本JRockit JVM是世界上最快的[JVM]畸颅。JRockit面向延遲敏感型應(yīng)用的解決方案JRockit Real Time提供以毫秒或微秒級的JVM響應(yīng)時間担巩,適合財(cái)務(wù)前端辦公、軍事指揮與控制和電信網(wǎng)絡(luò)的需要没炒。使用JRockit產(chǎn)品涛癌,客戶已經(jīng)體驗(yàn)到了顯著的性能提高(一些超過了70% )和硬件成本的減少(達(dá)50%)。

JRockit VM曾經(jīng)號稱“世界上速度最快的Java虛擬機(jī)”它是BEA公司在2002年從Appeal Virtual Machines公司收購的虛擬機(jī)送火。BEA公司將其發(fā)展為一款專門為服務(wù)器硬件和服務(wù)器端應(yīng)用場景高度優(yōu)化的虛擬機(jī)拳话,由于專注于服務(wù)器端應(yīng)用,它可以不太關(guān)注程序啟動速度种吸,因此JRockit內(nèi)部不包含解析器實(shí)現(xiàn)弃衍,全部代碼都靠即時編譯器編譯后執(zhí)行。除此之外坚俗,JRockit的垃圾收集器和MissionControl服務(wù)套件等部分的實(shí)現(xiàn)悴晰,在眾多Java虛擬機(jī)中也一直處于領(lǐng)先水平棵逊。

IBM J9 VM并不是IBM公司唯一的Java虛擬機(jī),不過是目前其主力發(fā)展的Java虛擬機(jī)。IBM J9 VM原本是內(nèi)部開發(fā)代號纬纪,正式名稱是“IBM Technology for Java Virtual Machine”求豫,簡稱IT4J右蒲,只是這個名字太拗口了一點(diǎn)幢妄,普及程度不如J9。J9 VM最初是由IBM Ottawa實(shí)驗(yàn)室一個名為SmallTalk的虛擬機(jī)擴(kuò)展而來的幢尚,當(dāng)時這個虛擬機(jī)有一個bug是由8k值定義錯誤引起的破停,工程師花了很長時間終于發(fā)現(xiàn)并解決了這個錯誤,此后這個版本的虛擬機(jī)就稱為K8了尉剩,后來擴(kuò)展出支持Java的虛擬機(jī)就被稱為J9了真慢。與BEA JRockit專注于服務(wù)器端應(yīng)用不同,IBM J9的市場定位與Sun HotSpot比較接近理茎,它是一款設(shè)計(jì)上從服務(wù)器端到桌面應(yīng)用再到嵌入式都全面考慮的多用途虛擬機(jī)黑界,J9的開發(fā)目的是作為IBM公司各種Java產(chǎn)品的執(zhí)行平臺,它的主要市場是和IBM產(chǎn)品(如IBM WebSphere等)搭配以及在IBM AIX和z/OS這些平臺上部署Java應(yīng)用功蜓。

5. Azul VM / BEA Liquid VM

我們平時所提及的“高性能Java虛擬機(jī)”一般是指HotSpot园爷、JRockit、J9這類在通用平臺上運(yùn)行的商用虛擬機(jī)式撼,但其實(shí)Azul VM和BEA Liquid VM這類特定硬件平臺專有的虛擬機(jī)才是“高性能”的武器童社。

Azul VM是Azul Systems 公司在HotSpot基礎(chǔ)上進(jìn)行大量改進(jìn),運(yùn)行于Azul Systems公司的專有硬件Vega系統(tǒng)上的Java虛擬機(jī)著隆,每個Azul VM實(shí)例都可以管理至少數(shù)十個CPU和數(shù)百GB內(nèi)存的硬件資源扰楼,并提供在巨大內(nèi)存范圍內(nèi)實(shí)現(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ā)的,可以直接運(yùn)行在自家Hypervisor系統(tǒng)上的JRockit VM的虛擬化版本币厕,Liquid VM不需要操作系統(tǒng)的支持列另,或者說它自己本身實(shí)現(xiàn)了一個專用操作系統(tǒng)的必要功能,如文件系統(tǒng)旦装、網(wǎng)絡(luò)支持等页衙。由虛擬機(jī)越過通用操作系統(tǒng)直接控制硬件可以獲得很多好處,如在線程調(diào)度時阴绢,不需要再進(jìn)行內(nèi)核態(tài)/用戶態(tài)的切換等店乐,這樣可以最大限度地發(fā)揮硬件的能力,提升Java程序的執(zhí)行性能呻袭。

6. Apache Harmony / Google Android Dalvik VM

Harmony VM和Dalvik VM只能稱做“虛擬機(jī)”眨八,而不能稱做“Java虛擬機(jī)”,但是這兩款虛擬機(jī)(以及所代表的技術(shù)體系)對最近幾年的Java世界產(chǎn)生了非常大的影響和挑戰(zhàn)棒妨,甚至有些悲觀的評論家認(rèn)為成熟的Java生態(tài)系統(tǒng)有崩潰的可能踪古。

Apache Harmony是一個Apache軟件基金會旗下以Apache License協(xié)議開源的實(shí)際兼容于JDK 1.5和JDK 1.6的Java程序運(yùn)行平臺含长,這個介紹相當(dāng)拗口券腔。它包含自己的虛擬機(jī)和Java庫,用戶可以在上面運(yùn)行Eclipse拘泞、Tomcat纷纫、Maven等常見的Java程序,但是它沒有通過TCK認(rèn)證陪腌,所以我們不得不用那么一長串拗口的語言來介紹它辱魁,而不能用一句“Apache的JDK”來說明。如果一個公司要宣布自己的運(yùn)行平臺“兼容于Java語言”诗鸭,那就必須要通過TCK(Technology Compatibility Kit)的兼容性測試染簇。Apache基金會曾要求Sun公司提供TCK的使用授權(quán),但是一直遭到拒絕强岸,直到Oracle公司收購了Sun公司之后锻弓,雙方關(guān)系越鬧越僵,最終導(dǎo)致Apache憤然退出JCP(Java Community Process)組織蝌箍,這是目前為止Java社區(qū)最嚴(yán)重的一次“分裂”青灼。

在Sun將JDK開源形成OpenJDK之后暴心,Apache Harmony開源的優(yōu)勢被極大地削弱,甚至連Harmony項(xiàng)目的最大參與者IBM公司也宣布辭去Harmony項(xiàng)目管理主席的職位杂拨,并參與OpenJDK項(xiàng)目的開發(fā)专普。雖然Harmony沒有經(jīng)過真正大規(guī)模的商業(yè)運(yùn)用,但是它的許多代碼(基本上是Java庫部分的代碼)被吸納進(jìn)IBM的JDK 7實(shí)現(xiàn)及Google Android SDK之中弹沽,尤其是對Android的發(fā)展起到了很大的推動作用檀夹。

說到Android,這個時下最熱門的移動數(shù)碼設(shè)備平臺在最近幾年間的發(fā)展過程中所取得的成果已經(jīng)遠(yuǎn)遠(yuǎn)超越了Java ME在過去十多年所獲得的成果策橘,Android讓Java語言真正走進(jìn)了移動數(shù)碼設(shè)備領(lǐng)域击胜,只是走的并非Sun公司原本想象的那一條路。

Dalvik VM是Android平臺的核心組成部分之一役纹,它的名字來源于冰島一個名為Dalvik的小漁村偶摔。Dalvik VM并不是一個Java虛擬機(jī),它沒有遵循Java虛擬機(jī)規(guī)范促脉,不能直接執(zhí)行Java的Class文件辰斋,使用的是寄存器架構(gòu)而不是JVM中常見的棧架構(gòu)。但是它與Java又有著千絲萬縷的聯(lián)系瘸味,它執(zhí)行的dex(Dalvik Executable)文件可以通過Class文件轉(zhuǎn)化而來宫仗,使用Java語法編寫應(yīng)用程序,可以直接使用大部分的Java API等旁仿。目前Dalvik VM隨著Android一起處于迅猛發(fā)展階段藕夫,在Android 2.2中已提供即時編譯器實(shí)現(xiàn),在執(zhí)行性能上有了很大的提高枯冈。

7. Microsoft JVM及其他

在十幾年的Java虛擬機(jī)發(fā)展過程中毅贮,除去上面介紹的那些被大規(guī)模商業(yè)應(yīng)用過的Java虛擬機(jī)外,還有許多虛擬機(jī)是不為人知的或者曾經(jīng)“絢麗”過但最終湮滅的尘奏。我們以其中微軟公司的JVM為例來介紹一下滩褥。

也許Java程序員聽起來可能會覺得驚訝,微軟公司曾經(jīng)是Java技術(shù)的鐵桿支持者(也必須承認(rèn)炫加,與Sun公司爭奪Java的控制權(quán)瑰煎,令Java從跨平臺技術(shù)變?yōu)榻壎ㄔ赪indows上的技術(shù)是微軟公司的主要目的)。在Java語言誕生的初期(1996年~1998年俗孝,以JDK 1.2發(fā)布為分界)酒甸,它的主要應(yīng)用之一是在瀏覽器中運(yùn)行Java Applets程序,微軟公司為了在IE3中支持Java Applets應(yīng)用而開發(fā)了自己的Java虛擬機(jī)赋铝,雖然這款虛擬機(jī)只有Windows平臺的版本插勤,卻是當(dāng)時Windows下性能最好的Java虛擬機(jī),它在1997年和1998年連續(xù)兩年獲得了《PC Magazine》雜志的“編輯選擇獎”。但好景不長饮六,在1997年10月其垄,Sun公司正式以侵犯商標(biāo)、不正當(dāng)競爭等罪名控告微軟公司卤橄,在隨后對微軟公司的壟斷調(diào)查之中绿满,這款虛擬機(jī)也曾作為證據(jù)之一被呈送法庭。這場官司的結(jié)果是微軟公司賠償2000萬美金給Sun公司(最終微軟公司因壟斷賠償給Sun公司的總金額高達(dá)10億美元)窟扑,承諾終止其Java虛擬機(jī)的發(fā)展喇颁,并逐步在產(chǎn)品中移除Java虛擬機(jī)相關(guān)功能。具有諷刺意味的是嚎货,到最后在Windows XP SP3中Java虛擬機(jī)被完全抹去的時候橘霎,Sun公司卻又到處登報(bào)希望微軟公司不要這樣做。Windows XP高級產(chǎn)品經(jīng)理Jim Cullinan稱:“我們花費(fèi)了3年的時間和Sun打官司殖属,當(dāng)時他們試圖阻止我們在Windows中支持Java姐叁,現(xiàn)在我們這樣做了,可他們又在抱怨洗显,這太具有諷刺意味了外潜。”

我們試想一下挠唆,如果當(dāng)年Sun公司沒有起訴微軟公司处窥,微軟公司繼續(xù)保持著對Java技術(shù)的熱情,那Java的世界會變得怎么樣呢玄组?.NET技術(shù)是否會發(fā)展起來滔驾?但歷史是沒有假設(shè)的。

五俄讹、JVM相關(guān)問題

問:堆和棧有什么區(qū)別

答:堆是存放對象的哆致,但是對象內(nèi)的臨時變量是存在棧內(nèi)存中,如例子中的methodVar是在運(yùn)行期存放到棧中的颅悉。

棧是跟隨線程的沽瞭,有線程就有棧迁匠,堆是跟隨JVM的剩瓶,有JVM就有堆內(nèi)存。

問:堆內(nèi)存中到底存在著什么東西城丧?

答:對象延曙,包括對象變量以及對象方法。

問:類變量和實(shí)例變量有什么區(qū)別亡哄?

答:靜態(tài)變量是類變量枝缔,非靜態(tài)變量是實(shí)例變量,直白的說,有static修飾的變量是靜態(tài)變量愿卸,沒有static修飾的變量是實(shí)例變量灵临。靜態(tài)變量存在方法區(qū)中,實(shí)例變量存在堆內(nèi)存中趴荸。

問:我聽說類變量是在JVM啟動時就初始化好的儒溉,和你這說的不同呀!

答:那你是道聽途說发钝,信我的顿涣,沒錯。

問:Java的方法(函數(shù))到底是傳值還是傳址酝豪?

答:都不是涛碑,是以傳值的方式傳遞地址,具體的說原生數(shù)據(jù)類型傳遞的值孵淘,引用類型傳遞的地址蒲障。對于原始數(shù)據(jù)類型,JVM的處理方法是從Method Area或Heap中拷貝到Stack瘫证,然后運(yùn)行frame中的方法晌涕,運(yùn)行完畢后再把變量指拷貝回去。

問:為什么會產(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扭仁,于是就會報(bào)OutOfMemory了垮衷,可能以后的對象申請的內(nèi)存都只要0.9M,于是就只出現(xiàn)一次OutOfMemory乖坠,GC也正常了搀突,看起來像偶發(fā)事件,就是這么回事熊泵。 但如果此時GC沒有回收就會產(chǎn)生掛起情況仰迁,系統(tǒng)不響應(yī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)存了检盼,這個很常見祠肥,檢查應(yīng)用或調(diào)整堆內(nèi)存大小。

“PermGen space”是因?yàn)橛谰么鎯^(qū)滿了梯皿,這個也很常見仇箱,一般在熱發(fā)布的環(huán)境中出現(xiàn),是因?yàn)槊看伟l(fā)布應(yīng)用系統(tǒng)都不重啟东羹,久而久之永久存儲區(qū)中的死對象太多導(dǎo)致新對象無法申請內(nèi)存剂桥,一般重新啟動一下即可。

問:為什么會產(chǎn)生StackOverflowError属提?

答:因?yàn)橐粋€線程把Stack內(nèi)存全部耗盡了权逗,一般是遞歸函數(shù)造成的。

問:一個機(jī)器上可以看多個JVM嗎冤议?JVM之間可以互訪嗎斟薇?

答:可以多個JVM,只要機(jī)器承受得了恕酸。JVM之間是不可以互訪堪滨,你不能在A-JVM中訪問B-JVM的Heap內(nèi)存,這是不可能的蕊温。在以前老版本的JVM中袱箱,會出現(xiàn)A-JVM Crack后影響到B-JVM,現(xiàn)在版本非常少見义矛。

問:為什么Java要采用垃圾回收機(jī)制发笔,而不采用C/C++的顯式內(nèi)存管理?

答:為了簡單凉翻,內(nèi)存管理不是每個程序員都能折騰好的了讨。

問:為什么你沒有詳細(xì)介紹垃圾回收機(jī)制?

答:垃圾回收機(jī)制每個JVM都不同制轰,JVM Specification只是定義了要自動釋放內(nèi)存前计,也就是說它只定義了垃圾回收的抽象方法,具體怎么實(shí)現(xiàn)各個廠商都不同艇挨,算法各異残炮,這東西實(shí)在沒必要深入。

問:JVM中到底哪些區(qū)域是共享的缩滨?哪些是私有的?

答:Heap和Method Area是共享的,其他都是私有的

問:什么是JIT脉漏,你怎么沒說苞冯?

答:JIT是指Just In Time,有的文檔把JIT作為JVM的一個部件來介紹侧巨,有的是作為執(zhí)行引擎的一部分來介紹舅锄,這都能理解。Java剛誕生的時候是一個解釋性語言司忱,別噓皇忿,即使編譯成了字節(jié)碼(byte code)也是針對JVM的,它需要再次翻譯成原生代碼(native code)才能被機(jī)器執(zhí)行坦仍,于是效率的擔(dān)憂就提出來了鳍烁。Sun為了解決該問題提出了一套新的機(jī)制,好繁扎,你想編譯成原生代碼幔荒,沒問題,我在JVM上提供一個工具梳玫,把字節(jié)碼編譯成原生碼爹梁,下次你來訪問的時候直接訪問原生碼就成了,于是JIT就誕生了提澎,就這么回事姚垃。

問:JVM還有哪些部分是你沒有提到的?

答:JVM是一個異常復(fù)雜的東西盼忌,寫一本磚頭書都不為過莉炉,還有幾個要說明的:

  • 常量池(constant pool):按照順序存放程序中的常量,并且進(jìn)行索引編號的區(qū)域碴犬。比如int i =100絮宁,這個100就放在常量池中。
  • 安全管理器(Security Manager):提供Java運(yùn)行期的安全控制服协,防止惡意攻擊绍昂,比如指定讀取文件,寫入文件權(quán)限偿荷,網(wǎng)絡(luò)訪問窘游,創(chuàng)建進(jìn)程等等,Class Loader在Security Manager認(rèn)證通過后才能加載class文件的跳纳。
  • 方法索引表(Methods table)忍饰,記錄的是每個method的地址信息,Stack和Heap中的地址指針其實(shí)是指向Methods table地址寺庄。

問:為什么不建議在程序中顯式的生命System.gc()艾蓝?

答:因?yàn)轱@式聲明是做堆內(nèi)存全掃描力崇,也就是Full GC,是需要停止所有的活動的(Stop The World Collection)赢织,你的應(yīng)用能承受這個嗎亮靴?

問:JVM有哪些調(diào)整參數(shù)?

答:非常多于置,堆內(nèi)存茧吊、棧內(nèi)存的大小都可以定義,甚至是堆內(nèi)存的三個部分八毯、新生代的各個比例都能調(diào)整搓侄。

六、Jvm調(diào)優(yōu)與性能優(yōu)化

今天是JVM的生日话速,來了解下JVM的發(fā)展歷史吧

在互聯(lián)網(wǎng)公司面試中讶踪,架構(gòu)的底層一定是面試官會問到的問題,針對面試官一般會提到的問題尿孔,我錄制了一些底層原理的錄像視頻俊柔,加群619881427可以免費(fèi)獲取這些錄像,里面有些分布式活合,微服務(wù)雏婶,性能優(yōu)化,Spring白指,MyBatis的等源碼知識點(diǎn)的錄像視頻留晚。上圖的性能優(yōu)化只是其中的一小部分,這些視頻都是我找一些資深架構(gòu)師朋友一起錄制出來的告嘲,視頻希望能夠幫助到以下幾類程序員:

1.對現(xiàn)在的薪資不滿错维,想要跳槽,卻對自己的技術(shù)沒有信心橄唬,不知道如何面對面試官赋焕。

2.想從傳統(tǒng)行業(yè)轉(zhuǎn)行到互聯(lián)網(wǎng)行業(yè),但沒有接觸過互聯(lián)網(wǎng)技術(shù)仰楚。

3.工作1 - 5年需要提升自己的核心競爭力隆判,但學(xué)習(xí)沒有系統(tǒng)化,不知道自己接下來要學(xué)什么才是正確的僧界,踩坑后又不知道找誰侨嘀,百度后依然不知所以然。

4.工作5 - 10年無法突破技術(shù)瓶頸(運(yùn)用過很多技術(shù)捂襟,在公司一直寫著業(yè)務(wù)代碼咬腕,卻依然不懂底層實(shí)現(xiàn)原理)

如果你現(xiàn)在正處于我上述所說的幾個階段可以加下我的群來學(xué)習(xí)。而且我也能夠提供一些面試指導(dǎo)葬荷,職業(yè)規(guī)劃等建議涨共。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纽帖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子煞赢,更是在濱河造成了極大的恐慌抛计,老刑警劉巖哄孤,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件照筑,死亡現(xiàn)場離奇詭異,居然都是意外死亡瘦陈,警方通過查閱死者的電腦和手機(jī)凝危,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晨逝,“玉大人蛾默,你說我怎么就攤上這事∽矫玻” “怎么了支鸡?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趁窃。 經(jīng)常有香客問我牧挣,道長,這世上最難降的妖魔是什么醒陆? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任瀑构,我火速辦了婚禮,結(jié)果婚禮上刨摩,老公的妹妹穿的比我還像新娘寺晌。我一直安慰自己,他們只是感情好澡刹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布呻征。 她就那樣靜靜地躺著,像睡著了一般罢浇。 火紅的嫁衣襯著肌膚如雪陆赋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天己莺,我揣著相機(jī)與錄音奏甫,去河邊找鬼。 笑死凌受,一個胖子當(dāng)著我的面吹牛阵子,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胜蛉,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼挠进,長吁一口氣:“原來是場噩夢啊……” “哼色乾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起领突,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤暖璧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后君旦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澎办,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年金砍,在試婚紗的時候發(fā)現(xiàn)自己被綠了局蚀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恕稠,死狀恐怖琅绅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鹅巍,我是刑警寧澤千扶,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站骆捧,受9級特大地震影響澎羞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凑懂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一煤痕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧接谨,春花似錦摆碉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扫夜,卻和暖如春楞泼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背笤闯。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工堕阔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颗味。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓超陆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浦马。 傳聞我的和親對象是個殘疾皇子时呀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容