中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

替老外做網(wǎng)站中國(guó)國(guó)家人事人才培訓(xùn)網(wǎng)官網(wǎng)

替老外做網(wǎng)站,中國(guó)國(guó)家人事人才培訓(xùn)網(wǎng)官網(wǎng),鄭州網(wǎng)站維護(hù),互聯(lián)網(wǎng)營(yíng)銷師考試這篇文章本來只是想講一下class文件格式,講著講著越講越多。JVM這一塊吧,知識(shí)比較散比較多,如果深研究下去如死扣《深入理解Java虛擬機(jī)》,這本書很深很細(xì),全記住是不可能的,其實(shí)也沒必要。趁這個(gè)機(jī)會(huì)直接把…

這篇文章本來只是想講一下class文件格式,講著講著越講越多。JVM這一塊吧,知識(shí)比較散比較多,如果深研究下去如死扣《深入理解Java虛擬機(jī)》,這本書很深很細(xì),全記住是不可能的,其實(shí)也沒必要。趁這個(gè)機(jī)會(huì)直接把標(biāo)題中的這些的主要知識(shí)點(diǎn)都總結(jié)一下,不會(huì)過深,也不會(huì)是太浮于表面的八股文,總結(jié)一下比較好記,也省的后面自己再忘了。

主要內(nèi)容包括以下幾部分:
class文件格式
JVM加載class文件流程
JVM運(yùn)行時(shí)內(nèi)存區(qū)域
對(duì)象分配內(nèi)存流程

一,class文件格式

在idea中,一般我們直接點(diǎn)開target目錄中的class文件,idea會(huì)幫助我們反編譯后展示為java文件,那么如何觀察到class文件的格式呢?

這里我們需要在idea中安裝一個(gè)Jclasslib的插件,如下圖所示:
在這里插入圖片描述
鼠標(biāo)光標(biāo)停在類名上,點(diǎn)擊view->show bytecode with jclasslib,即可查看到class文件。如下圖所示:

在這里插入圖片描述
class文件[注2]包含但不限于以下幾個(gè)部分,

開頭是著名的魔數(shù)0xCAFEBABE(如果沒有特殊說明,這里及下面的進(jìn)制都是16進(jìn)制),CAFEBABE這個(gè)魔數(shù)是用于標(biāo)識(shí)和校驗(yàn)這個(gè)文件是否是一個(gè)class文件的。

此外,class文件中還包括如Minor Version、Major Version,用于標(biāo)識(shí)Java版本號(hào);

constant_pool(常量池),常量池用于存儲(chǔ)字面量(Literal)符號(hào)引用(Symbolic References)。字面量比較接近Java語(yǔ)言層面的常量概念,如文本字符串、被聲明為final的常量值等。而符號(hào)引用則屬于編譯原理方面的概念,主要包含下面幾類常量[1]:
被模塊導(dǎo)出或者開放的包(Package)
類和接口的全限定名(Fully Qualified Name)
字段的名稱和描述符(Descriptor)
方法的名稱和描述符()
方法句柄和方法類型(Method Handle、Method Type、Invoke Dynamic)
動(dòng)態(tài)調(diào)用點(diǎn)和動(dòng)態(tài)常量(Dynamically-Computed Call Site、Dynamically-Computed Constant)
常量池中的這些常量和符號(hào)引用,在JVM運(yùn)行時(shí)會(huì)存放到方法區(qū)中的常量池中[1]。而如Fields、Methods等元數(shù)據(jù)信息,存放在方法區(qū)中。

另外,什么是符號(hào)引用呢?這就涉及到了JVM的懶加載機(jī)制[2],就是說在編譯成字節(jié)碼class文件后,JVM不會(huì)立即加載class文件,而是用到的時(shí)候再進(jìn)行加載[注1]。這就導(dǎo)致了class文件在被編譯出來后,無法立即被分配到內(nèi)存,也就沒有直接指向內(nèi)存的指針。那么,我們的字節(jié)碼指令,又是如何調(diào)用類、方法、成員變量的呢?

在字節(jié)碼class文件中,方法、成員變量、類以全限定名(即字符串常量)的方式被引用。如下圖所示,Fieldref_info,即存儲(chǔ)指向成員變量的指針(在下圖中舉例的是指向字符串String s),可以看到,描述了其類的全限定名、成員變量的名字和其類型的全限定名,點(diǎn)擊跳轉(zhuǎn)到字段,會(huì)跳到字段中,即完成了通過字符串常量作為指針,跳轉(zhuǎn)到字段/方法/類的功能,這就是所謂的字符引用,說白了就是把全限定名的字符串作為引用的標(biāo)識(shí)。

這些符號(hào)引用一部分會(huì)在類加載階段或者第一次使用的時(shí)候就要被轉(zhuǎn)化為直接引用,這種轉(zhuǎn)換成為靜態(tài)解析。另外一部分將在每一次運(yùn)行期間都轉(zhuǎn)化為直接引用,這部分就稱為動(dòng)態(tài)連接[1]。

java虛擬機(jī)支持5種方法調(diào)用字節(jié)碼指令:
invokestatic:調(diào)用靜態(tài)方法
invokespecial:用于調(diào)用實(shí)例構(gòu)造器()方法、私有方法和父類中的方法
invokevirtual:調(diào)用所有的虛方法
invokeinterface:調(diào)用接口方法,會(huì)在運(yùn)行時(shí)再確定一個(gè)實(shí)現(xiàn)該接口的對(duì)象
invokedynamic:先在運(yùn)行時(shí)動(dòng)態(tài)解析出調(diào)用帶你限定符所引用的方法,然后再執(zhí)行該方法。前面4條調(diào)用指令,分派邏輯都固化在Java虛擬機(jī)內(nèi)部,而invokedynamic指令的分派邏輯是由用戶設(shè)定的引導(dǎo)方法來決定的。

其中只要能被invokestatic和invokespecial指令調(diào)用的方法,都可以在解析階段中確定唯一的調(diào)用版本,Java語(yǔ)言里符合這個(gè)條件的方法共有靜態(tài)方法、私有方法、實(shí)例構(gòu)造器、父類方法4種,再加上被final修飾的方法(盡管它使用invokevirtual指令調(diào)用),這5種方法調(diào)用會(huì)在類加載的時(shí)候就可以把符號(hào)引用解析為該方法的直接引用。這些方法統(tǒng)稱為“非虛方法”(Non-Virtual-Method),與之相反,其他方法就被稱為“虛方法”[1]。

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

講完了常量池,class文件中剩下的就比較好講了。如描述字段的表fields,描述方法的表methods,描述接口的表等等。這些就不展開講了,如果對(duì)其他部分感興趣,可以自己去查資料或者自己下一個(gè)jclasslib去看一看。

二,JVM加載class文件流程

在javac編譯完class文件后,顯而易見,如果要使用這些類,需要去加載它們(這里說的加載,指的是廣義上的加載,不是loading這一步)。JVM加載class文件,分為以下幾步,

在這里插入圖片描述

第一步,加載(loading),《深入理解Java虛擬機(jī)》中是這么說的:*通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流,將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法去這個(gè)類的各種數(shù)據(jù)的訪問入口。*聽起來是有點(diǎn)復(fù)雜,其實(shí)就是把雙親委派機(jī)制的工作內(nèi)容說出來了:通過類的全限定名,獲取其字節(jié)流,在堆中申請(qǐng)class對(duì)象的內(nèi)存空間,把類的各種元數(shù)據(jù)如方法表、屬性表、常量池等放入方法區(qū)。雙親委派機(jī)制就是用來加載類的,具體的可以看我上一篇文章,講的就是雙親委派機(jī)制是如何工作的[4]。

第二步,連接(linking),這一步中分3小步。其中第一小步,驗(yàn)證(verification),驗(yàn)證文件格式(如魔數(shù)是否為CAFEBABE、主次版本號(hào)等)、驗(yàn)證元數(shù)據(jù)、驗(yàn)證字節(jié)碼、驗(yàn)證符號(hào)引用。總之就是要驗(yàn)證文件格式是否符合JVM規(guī)范,看看是否是一個(gè)合格的class文件格式;第二小步,準(zhǔn)備(preparation),給靜態(tài)變量賦默認(rèn)值;第三小步,解析(resolution),將常量池內(nèi)的符號(hào)引用替換為直接引用,即前面提到的靜態(tài)解析。

第三步,初始化(initializing),這一階段會(huì)調(diào)用類構(gòu)造器< clinit>()。

需要注意的是,< clinit>()構(gòu)造方法,并不是實(shí)例對(duì)象的構(gòu)造方法< init>()。《深入理解Java虛擬機(jī)》中講:< clinit>()構(gòu)造方法是由編譯器自動(dòng)收集類中的所有類變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊(static{})中的語(yǔ)句合并產(chǎn)生的,編譯器收集的順序是由語(yǔ)句在源文件中出現(xiàn)的順序決定的。 我個(gè)人的理解就是,在loading階段申請(qǐng)了這個(gè)類的class對(duì)象的內(nèi)存,在initializing階段,會(huì)通過編譯器自動(dòng)生成的類構(gòu)造器方法來完成類class對(duì)象的初始化,即給靜態(tài)變量和靜態(tài)語(yǔ)句塊中的變量賦初始值。畢竟靜態(tài)變量是類的成員變量。

三,JVM運(yùn)行時(shí)內(nèi)存區(qū)域

前文講了編譯出的class文件結(jié)構(gòu),JVM加載class文件流程,剩下的我們聊一下JVM在運(yùn)行時(shí)的內(nèi)存區(qū)域的劃分。

JVM內(nèi)存可以劃分為程序計(jì)數(shù)器(Program Counter, PC)、Java虛擬機(jī)棧(Java Virtual Machine stack, JVM stack)、本地方法棧(native method stacks)、方法區(qū)(method area)、堆(Heap)直接內(nèi)存(Derict Memory)。

其中程序計(jì)數(shù)器和Java虛擬機(jī)棧是線程私有的,本地方法棧、方法區(qū)、堆、直接內(nèi)存都是線程公有的。

程序計(jì)數(shù)器,這一塊內(nèi)存區(qū)域較小,可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。

Java虛擬機(jī)棧,虛擬機(jī)棧描述的是Java方法執(zhí)行的線程內(nèi)存模型,每個(gè)方法被執(zhí)行的時(shí)候,Java虛擬機(jī)都會(huì)同步創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)連接、方法出口等信息。每一個(gè)方法被調(diào)用直至執(zhí)行完畢的過程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過程。

對(duì)于執(zhí)行引擎來說,在活動(dòng)線程中,只有位于棧頂?shù)姆椒ú攀沁\(yùn)行的,只有位于棧頂?shù)臈攀巧У?#xff0c;其被稱為”當(dāng)前棧幀“(Current Stack Frame),與這個(gè)棧幀所關(guān)聯(lián)的方法被稱為”當(dāng)前方法“(Current Method)。執(zhí)行引擎所運(yùn)行的所有字節(jié)碼指令都只針對(duì)當(dāng)前棧幀進(jìn)行操作。

每一個(gè)棧幀都包括了局部變量表、操作數(shù)棧、動(dòng)態(tài)連接、方法返回地址和一些額外的附加信息。

其中,局部變量表(Local Variables Table)是一組變量值的存儲(chǔ)空間,用于存放方法參數(shù)和方法內(nèi)部定義的局部變量。

操作數(shù)棧(Operand Stack)也常被稱為操作棧,它是一個(gè)后入先出(Last In First Out, LIFO)棧。當(dāng)一個(gè)方法剛剛開始執(zhí)行的時(shí)候,這個(gè)方法的操作數(shù)棧是空的,在方法的執(zhí)行過程中,會(huì)有各種字節(jié)碼指令往操作數(shù)棧中寫入和提取內(nèi)容,也就是出棧和入棧操作。

每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用,持有這個(gè)引用是為了支持方法調(diào)用過程中的動(dòng)態(tài)連接。實(shí)際上因?yàn)橛械姆椒ㄟM(jìn)行靜態(tài)解析而不是動(dòng)態(tài)連接(還記得嗎,能被invokestatic和invokespecial指令調(diào)用的方法和被final修飾的方法都會(huì)進(jìn)行靜態(tài)解析),不是所有棧幀的這個(gè)方法引用都能進(jìn)行動(dòng)態(tài)連接。

這么描述可能有點(diǎn)抽象,我們結(jié)合jclasslib來看一下

很簡(jiǎn)單的一段代碼

在這里插入圖片描述

對(duì)應(yīng)的字節(jié)碼

在這里插入圖片描述

下面的LocalVariable Table為局部變量表

在這里插入圖片描述

看到字節(jié)碼望而生畏,這么多字節(jié)碼指令記不住怎么辦?字節(jié)碼不需要記,需要的話查就好了(一般也用不到debug到字節(jié)碼的程度吧,除了一些面試用的題…),左鍵單擊字節(jié)碼指令,再點(diǎn)擊Show JVM Spec,即可跳轉(zhuǎn)到Java虛擬機(jī)規(guī)范中對(duì)應(yīng)字節(jié)碼的查詢結(jié)果[5]。

在這里插入圖片描述

在這里插入圖片描述

m方法字節(jié)碼流程如下:
iconst_0,《JVM虛擬機(jī)規(guī)范》[5]中規(guī)定如下,因此iconst_0意為將整數(shù)int 0壓入操作數(shù)棧

在這里插入圖片描述

istore_1,注意description中的描述,istore_< n>中的n,是當(dāng)前棧幀的局部變量表的索引值,istore_1是將操作數(shù)棧頂?shù)恼麛?shù)類型變量,即棧頂?shù)臄?shù)0彈出操作數(shù)棧,并且賦值給局部變量表索引為1的位置,即給局部變量i賦值為0。iconst_0和istore_1結(jié)合起來,就是代碼int i = 0;

在這里插入圖片描述

在這里插入圖片描述

iload_1,將局部變量表中索引為1的位置的數(shù)據(jù)彈出,并壓入操作數(shù)棧中。

在這里插入圖片描述

iinc 1 by 1,將局部變量表中索引為1位置的數(shù)+1 。注意這個(gè)操作和操作數(shù)棧沒有關(guān)系。完成了i++

在這里插入圖片描述

istore_2,將操作數(shù)棧中的數(shù)0彈出,賦值給局部變量表中2號(hào)索引位置。即int j = 0;

最后,返回,沒有任何返回值。如果當(dāng)前棧幀(m方法)下面還有其他棧幀,當(dāng)前棧幀return后彈出,會(huì)由調(diào)用m方法的棧幀繼續(xù)執(zhí)行,成為新的當(dāng)前棧幀。當(dāng)然,這里m方法沒有任何調(diào)用,到此,字節(jié)碼結(jié)束。

有一些面試題會(huì)考i = i++和i = ++i的區(qū)別,實(shí)質(zhì)上就是字節(jié)碼istore_1和iinc 1 by 1順序調(diào)換導(dǎo)致的。當(dāng)然任何人都不會(huì)在項(xiàng)目中這么寫代碼,考這個(gè)純粹為了考而考了…

在這里插入圖片描述

Java虛擬機(jī)棧說到這里。

本地方法棧(Native Method Stacks),與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,其區(qū)別是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的本地(Native)方法服務(wù)。《Java虛擬機(jī)規(guī)范》對(duì)本地方法棧中的方法使用的語(yǔ)言、使用方式和數(shù)據(jù)結(jié)構(gòu)并沒有任何強(qiáng)制規(guī)定,因此具體的虛擬機(jī)可以根據(jù)需要自由實(shí)現(xiàn)它[1]。

Java堆(Java Heap),對(duì)于Java應(yīng)用來說,Java堆是虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,Java世界里“幾乎”所有的對(duì)象實(shí)例都在這里分配內(nèi)存。Java堆是垃圾收集器管理的內(nèi)存區(qū)域,因此一些資料中它也被稱作”GC堆“(Garbage Collected Heap)[1]。

從回收內(nèi)存的角度看,由于現(xiàn)代垃圾收集器大部分都是基于分代收集理論設(shè)計(jì)的,所以Java堆中經(jīng)常會(huì)出現(xiàn)”新生代“ ”老年代“ “永久代” “Eden空間” “From Survivor空間” "To Survivor空間"等名詞,在這里筆者想先說明的是這些區(qū)域劃分僅僅是一部分垃圾收集器的共同特性或者說設(shè)計(jì)風(fēng)格而已,而非某個(gè)Java虛擬機(jī)具體實(shí)現(xiàn)的固有內(nèi)存布局,更不是《Java虛擬機(jī)規(guī)范》里對(duì)Java堆的進(jìn)一步細(xì)致劃分[1]。

需要注意的是,盡管Java堆中可以劃分出多個(gè)線程私有的分配緩沖區(qū)(Thread Local Allocation Buffer, TLAB),以提升對(duì)象分配時(shí)的效率。TLAB占用伊甸區(qū)eden,默認(rèn)1%。用于給小對(duì)象在多線程的情況下不用競(jìng)爭(zhēng)eden區(qū)分配就可以申請(qǐng)空間,提高效率。

方法區(qū)(Method Area),線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類型信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存等數(shù)據(jù)。

其中,**運(yùn)行時(shí)常量池(Runtime Constant Pool)**是方法區(qū)的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息是常量池表(Constant Pool Table),用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池中。

說到方法區(qū),不得不提一下“永久代”這個(gè)概念,尤其是在JDK8之前,許多程序員習(xí)慣在HotSpot虛擬機(jī)上開發(fā)、部署程序,很多人都更愿意把方法區(qū)稱呼為“永久代”(Permanent Generation),或?qū)烧呋鞛橐徽劇1举|(zhì)上這兩者不是等價(jià)的,因?yàn)閮H僅是當(dāng)時(shí)的HotSpot虛擬機(jī)設(shè)計(jì)團(tuán)隊(duì)選擇把收集器的分代設(shè)計(jì)擴(kuò)展至方法區(qū),或者說使用分代來實(shí)現(xiàn)方法區(qū)而已,這樣使得HotSpot的垃圾收集器能夠像管理Java堆一樣管理這些內(nèi)存,省去專門為方法區(qū)編寫內(nèi)存管理代碼的工作。但是對(duì)于其他虛擬機(jī)實(shí)現(xiàn),譬如BEAJRockit、IBM J9等來說,是不存在永久代概念的。原則上如何實(shí)現(xiàn)方法區(qū)屬于虛擬機(jī)的實(shí)現(xiàn)細(xì)節(jié),不受《Java虛擬機(jī)規(guī)范》管束,并不要求統(tǒng)一。但是回過頭來看,當(dāng)年使用永久代來實(shí)現(xiàn)方法區(qū)的決定并不是一個(gè)好主意,這種設(shè)計(jì)使得Java應(yīng)用更容易遇到內(nèi)存溢出的問題。到了JDK7的HotSpot,已經(jīng)把原來存放在永久代的字符串常量池、靜態(tài)變量等移出,到了JDK8,終于完全廢棄了永久代的概念,改用與JRockit、J9一樣在本地內(nèi)存中實(shí)現(xiàn)的元空間(Meta Space)來代替,把JDK7中永久代還剩余的內(nèi)容(主要是類型信息)全部移到元空間中。

直接內(nèi)存(Derict Memory),直接內(nèi)存并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是《Java虛擬機(jī)規(guī)范》中定義的內(nèi)存區(qū)域。但是這部分內(nèi)存也被頻繁的使用,而且也可能導(dǎo)致OutOfMemoryError異常出現(xiàn),所以我們放到這里一起講解。

在JDK1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的I/O方式,它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過一個(gè)存儲(chǔ)在Java堆里面的DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬嗽贘ava堆和Native堆中來回復(fù)制數(shù)據(jù)。

顯然,本機(jī)直接內(nèi)存的分配不會(huì)收到Java堆大小的限制,但是,既然是內(nèi)存,則肯定還是會(huì)受到本機(jī)總內(nèi)存(包括物理內(nèi)存、SWAP分區(qū)或者分頁(yè)文件)大小以及處理器尋址空間的限制,一般服務(wù)器管理員配置虛擬機(jī)參數(shù)時(shí),會(huì)根據(jù)實(shí)際內(nèi)存去設(shè)置-Xmx等參數(shù)信息,但經(jīng)常忽略掉直接內(nèi)存,使得各個(gè)內(nèi)存區(qū)域綜合大于物理內(nèi)存限制(包括物理的和操作系統(tǒng)級(jí)的限制),從而導(dǎo)致動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn)OutOfMemoryError異常。

四,對(duì)象分配內(nèi)存的流程

我們通常堆(Heap)是用于存儲(chǔ)對(duì)象實(shí)例的,那么一個(gè)對(duì)象是直接就被分配到堆中嗎?并不是的。但是在了解對(duì)象的分配流程之前,我們需要先了解一些內(nèi)容。

棧上分配,滿足棧上分配的要求如下:
線程私有小對(duì)象
無逃逸
支持標(biāo)量替換

需要說明的是,棧上分配需要預(yù)先開啟標(biāo)量替換和逃逸分析才能使用[6],但是一般情況下,無需對(duì)棧上分配這兩項(xiàng)設(shè)置進(jìn)行更改和調(diào)優(yōu)。

其中,逃逸指的是這個(gè)對(duì)象被多個(gè)線程共享,無逃逸即這個(gè)對(duì)象就在這一段代碼中使用,沒有return出去[6];而標(biāo)量替換是說把一個(gè)對(duì)象中的字段直接分配到棧上,用于代替整個(gè)對(duì)象。

分配緩沖區(qū)(Thread Local Allocation Buffer, TLAB)(前文講過,這里再?gòu)?fù)述一遍),Java堆中可以劃分出多個(gè)線程私有的分配緩沖區(qū),以提升對(duì)象分配時(shí)的效率。TLAB占用伊甸區(qū)eden,默認(rèn)1%。用于給小對(duì)象在多線程的情況下不用競(jìng)爭(zhēng)eden區(qū)分配就可以申請(qǐng)空間,提高效率。滿足TLAB的條件如下:
小對(duì)象

一個(gè)對(duì)象分配內(nèi)存的流程如下
如果能夠棧上分配,就棧上分配;

剩下的對(duì)象,看看是否足夠大,如果足夠大,直接分配到老年代。

剩下的對(duì)象,看看是否滿足分配到TLAB,如果可以,分配到Eden區(qū)中的TLAB。

剩下的對(duì)象,分配到Eden區(qū)。

Eden區(qū)(包括TLAB)中的對(duì)象,等到年輕代空間滿了,會(huì)觸發(fā)YGC對(duì)年輕代進(jìn)行GC。經(jīng)歷了YGC后,還存活的對(duì)象,會(huì)遷移到S1區(qū)。S1區(qū)的對(duì)象經(jīng)歷YGC,會(huì)進(jìn)入S2區(qū);S2區(qū)的對(duì)象經(jīng)歷YGC,會(huì)進(jìn)入S1區(qū)。當(dāng)S1區(qū)和S2區(qū)的對(duì)象在經(jīng)歷了YGC后達(dá)到了進(jìn)入老年代的要求后,就可以進(jìn)入老年代。

老年代一旦觸發(fā)FGC,就會(huì)開始對(duì)整個(gè)堆進(jìn)行GC,存活的對(duì)象仍然留在老年代中,直到被GC回收。

在這里插入圖片描述

這里解釋一下關(guān)于JVM分代的一些術(shù)語(yǔ),如前文所述,部分JVM實(shí)現(xiàn)是按照分代設(shè)計(jì)的,按GC后存活次數(shù)分為老年代,年輕代。其中年輕代分為Eden區(qū)(伊甸區(qū)),S1區(qū)(Survivor1區(qū))、S2區(qū)(Survivor2區(qū))(也有的叫做S0區(qū)和S1區(qū),或者from區(qū)和to區(qū),都是一個(gè)意思),而老年代翻譯為old區(qū)或者tenured區(qū)。籠統(tǒng)的講,新生的對(duì)象會(huì)進(jìn)入Eden區(qū),經(jīng)歷了YGC會(huì)進(jìn)入S1區(qū),隨后在S1和S2區(qū)中間來回倒騰,直到進(jìn)入老年代為止。

YGC,即Young GC或者M(jìn)inor GC,是年輕代觸發(fā)GC后對(duì)年輕代的垃圾回收,包括Eden和S1 S2。

FGC,即Full GC或者M(jìn)ajor GC,是老年代觸發(fā)GC后對(duì)整個(gè)堆的垃圾回收。

前文說,”對(duì)象在S1和S2中間來回移動(dòng)直到滿足進(jìn)入老年代的條件為止“。進(jìn)入老年代的條件有二,滿足其一即可進(jìn)入老年代:

1,超過-XX:MaxTenuringThreshold指定次數(shù)(YGC)
對(duì)于常見的垃圾回收器,這個(gè)值是不同的,如

Parallel Scavenge   15
CMS    6
G1   15

2,滿足動(dòng)態(tài)年齡要求,即
在Survivor空間中低于或等于某年齡的所有對(duì)象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對(duì)象就可以直接進(jìn)入老年代,無需等到-XX:MaxTenuringThreshold中要求的年齡。

注1[3]:
嚴(yán)格來講,JVM沒有規(guī)定何時(shí)加載,但是規(guī)定了什么時(shí)候必須初始化。
new getstatic putstatic invokestatic指令,訪問final變量除外
java.lang.reflect對(duì)類進(jìn)行反射調(diào)用
初始化子類的時(shí)候,父類首先初始化
虛擬機(jī)啟動(dòng)時(shí),被執(zhí)行的主類必須初始化
動(dòng)態(tài)語(yǔ)言支持java.lang.invoke.MethodHandle解析的結(jié)果為REF_getstatic REF_putstatic REF_invokestatic 的方法句柄時(shí),該類必須初始化

注2:
一般來說,我們說Java文件編譯成為class文件字節(jié)碼,再由JVM的解釋器(Bytecode Interpreter)逐行解釋為機(jī)器碼,這是Java或者說JVM能夠跨平臺(tái)的關(guān)鍵。其實(shí)Java中有一種即時(shí)編譯機(jī)制JIT(Just In-Time compiler),這種機(jī)制可以將代碼編譯為機(jī)器碼,進(jìn)而不需要每次執(zhí)行熱點(diǎn)代碼都需要解釋執(zhí)行——編譯為機(jī)器碼后直接執(zhí)行機(jī)器碼即可。
Java默認(rèn)為混合模式,即混合使用解釋器+熱點(diǎn)代碼編譯,起始階段采用解釋執(zhí)行,通過熱點(diǎn)代碼探測(cè),檢測(cè)到熱點(diǎn)代碼后,對(duì)其進(jìn)行JIT即時(shí)編譯,并對(duì)其進(jìn)行編譯執(zhí)行。
-Xmixed 默認(rèn)混合模式,開始時(shí)為解釋執(zhí)行,啟動(dòng)速度較快,對(duì)熱點(diǎn)代碼進(jìn)行解釋和編譯
-Xint 使用解釋模式,啟動(dòng)很快,執(zhí)行稍慢
-Xcomp 使用純編譯模式,執(zhí)行很快,啟動(dòng)很慢
我們通過java -version,能夠看到最后顯示mixed mode,即此Java為混合模式??梢酝ㄟ^上述VM參數(shù)改變?yōu)榻忉屇J交蛘呒兙幾g模式。

在這里插入圖片描述

參考文章:
[1],深入理解Java虛擬機(jī),周志明,第三版
[2],談?wù)剬?duì)Java中符號(hào)引用和引用的理解
[3],03_class_loading_linking_initializing.pdf
[4],【JVM】簡(jiǎn)述類加載器及雙親委派機(jī)制
[5],Chapter 6. The Java Virtual Machine Instruction Set
[6],jvm:優(yōu)化-棧上分配

http://m.risenshineclean.com/news/62992.html

相關(guān)文章:

  • 武陟網(wǎng)站建設(shè)網(wǎng)站推廣找客戶
  • 網(wǎng)頁(yè)設(shè)計(jì)一頁(yè)多少錢整站優(yōu)化方案
  • 江蘇建設(shè)類高級(jí)工程師在那個(gè)網(wǎng)站公示百度免費(fèi)推廣平臺(tái)
  • wordpress怎么做淘客網(wǎng)站百度瀏覽器官網(wǎng)在線使用
  • 和wordpressseo是付費(fèi)還是免費(fèi)推廣
  • 南寧品牌網(wǎng)站設(shè)計(jì)公司如何免費(fèi)建立一個(gè)網(wǎng)站
  • 南平網(wǎng)站設(shè)計(jì)百度下載app
  • 幫一個(gè)公司做網(wǎng)站多少錢北京網(wǎng)絡(luò)營(yíng)銷推廣培訓(xùn)哪家好
  • wordpress多媒體設(shè)置成都比較靠譜的seo
  • 如何做自適應(yīng)網(wǎng)站珠海seo排名收費(fèi)
  • 荊門網(wǎng)站建設(shè)服務(wù)短視頻seo
  • 網(wǎng)站開發(fā)的例子關(guān)鍵詞優(yōu)化排名查詢
  • 合肥網(wǎng)站優(yōu)化哪家好熱門seo推廣排名穩(wěn)定
  • wordpress采集文章內(nèi)容深圳網(wǎng)站營(yíng)銷seo電話
  • 個(gè)人購(gòu)物網(wǎng)站怎么做中國(guó)500強(qiáng)最新排名
  • 免費(fèi)企業(yè)網(wǎng)站cms系統(tǒng)網(wǎng)絡(luò)營(yíng)銷成功案例ppt免費(fèi)
  • 濮陽(yáng)中強(qiáng)網(wǎng)站建設(shè)域名注冊(cè)需要多久
  • 直銷網(wǎng)寧波seo搜索平臺(tái)推廣專業(yè)
  • 西安抖音代運(yùn)營(yíng)公司seo優(yōu)化是什么
  • wordpress經(jīng)典漏洞搜外seo
  • 濰坊程序設(shè)計(jì)網(wǎng)站建設(shè)公司代運(yùn)營(yíng)哪家比較可靠
  • 做網(wǎng)站系統(tǒng)用什么語(yǔ)言鄭州seo教程
  • 如何制作旅游網(wǎng)站鄭州關(guān)鍵詞優(yōu)化顧問
  • 一個(gè)網(wǎng)站開發(fā)流程圖永久免費(fèi)跨境瀏覽app
  • 科技有限公司可以做網(wǎng)站建設(shè)嗎?廣州網(wǎng)絡(luò)推廣公司有哪些
  • 匯算清繳在哪個(gè)網(wǎng)站做百度貼吧廣告投放
  • 網(wǎng)站建設(shè)的三網(wǎng)合一廣州全網(wǎng)推廣
  • 網(wǎng)站域名登記證明在線搭建網(wǎng)站
  • 學(xué)校ftp服務(wù)器做網(wǎng)站泰安seo
  • 做網(wǎng)站賣廣告位賺錢嗎百度站長(zhǎng)工具平臺(tái)登錄