Jvm組成部分
1. PC寄存器/程序計數(shù)器
一塊小的內(nèi)存空間炫欺,作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器伶跷。分支蚓炬,循環(huán)松逊,跳轉(zhuǎn),異常處理肯夏,線程恢復(fù)等基礎(chǔ)功能都依賴計數(shù)器完成经宏。在任何一個時刻,一個處理器只會執(zhí)行一條線程中的指令驯击,因此烁兰,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程需要一個獨立的程序計數(shù)器(私有內(nèi)存)徊都。Java方法的計數(shù)器記錄正在執(zhí)行的虛擬機字節(jié)碼指令的地址沪斟,Native方法的計數(shù)器為空。計數(shù)器不存在OutofMemoryError.
2. Jvm棧
Jvm棧也是線程私有的暇矫,生命周期與線程相同主之。Jvm棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會創(chuàng)建一個棧幀(stackframe)用于存儲局部變量表,操作棧李根,動態(tài)鏈接槽奕,方法出口等信息。每一個方法被調(diào)用直至執(zhí)行完成的過程房轿,就對應(yīng)著一個棧幀在Jvm棧從入棧到出棧的過程史翘。局部變量表存放了基本數(shù)據(jù)類型(boolean,byte冀续,char琼讽,short,int洪唐,float钻蹬,long,double)凭需,對象引用(指向?qū)ο蟮刂返闹羔槪┖蛂eturnAddress(指向一條字節(jié)碼指令的地址)问欠。在方法運行期間不會改變局部變量表大小。
3. 本地方法棧
本地方法棧作用與Jvm棧作用類似粒蜈,區(qū)別不過是Jvm棧執(zhí)行的是Java方法顺献,本地方法棧執(zhí)行的是Native方法。
4. Jvm堆
Jvm堆是Jvm內(nèi)存最大的一塊枯怖,被所有線程所共享注整。Jvm堆在Jvm啟動時創(chuàng)建,此內(nèi)存區(qū)域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內(nèi)存肿轨。Jvm堆是垃圾收集器(GC)管理的主要區(qū)域寿冕。Jvm堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可椒袍。因為堆是Jvm中所有線程所共享的驼唱,因此在其上進行對象內(nèi)存分配均需要進行加鎖,這也導(dǎo)致了new對象的開銷是比較大的驹暑。Sun Hotspot Jvm為了提升對象內(nèi)存分配的效率玫恳,對于所創(chuàng)建的線程都會分配一塊獨立的空間TLAB(Thread Local Allocation Buffer),其大小由Jvm根據(jù)運行的情況計算而得优俘,在TLAB上分配對象不用加鎖京办,因此Jvm給線程分配對象的內(nèi)存時會盡可能的在TLAB上分配,如果對象過大兼吓,則仍需在堆空間分配臂港。TLAB僅作用于Eden Space森枪。
5. 方法區(qū)
與Jvm堆一樣视搏,方法區(qū)是各個線程共享的區(qū)域,它用于存儲已被虛擬機加載的類信息县袱,常量浑娜,靜態(tài)變量,即時編譯器編譯后的代碼等數(shù)據(jù)式散。方法區(qū)也可以叫永生代筋遭,但是Hotspot準(zhǔn)備放棄永生代,使用Native Memory來實現(xiàn)方法區(qū)暴拄。相對而言漓滔,GC在這個區(qū)域比較少的出現(xiàn),這個區(qū)域內(nèi)回收目標(biāo)主要是常量池和對類型的卸載乖篷。
6. 運行時常量池
運行時常量池是方法區(qū)的一部分,這里存放的是類中的固定的常量信息,方法和Field的引用信息捌臊。
Jvm垃圾回收機制
觸發(fā)GC的條件:
1)GC在優(yōu)先級最低的線程中進行或链,一般在應(yīng)用程序空閑,即沒有應(yīng)用程序在運行時鲸沮,被調(diào)用琳骡。
2)例外: 當(dāng)Jvm堆內(nèi)存不足時,GC會被調(diào)用讼溺。當(dāng)應(yīng)用線程正在運行楣号,并且在運行過程中創(chuàng)建對象,若這時內(nèi)存不足,Jvm會強制調(diào)用GC竖席。若一次GC之后仍不能滿足內(nèi)存分配耘纱,Jvm會再次進行兩次GC,若仍不能滿足毕荐,Jvm報OutofMemoryError,Java應(yīng)用停止束析。
GC的Generation算法(分代收集算法)
分代收集算法是大部分Jvm的垃圾收集器采用的算法。他的核心思想是根據(jù)對象存活的生命周期憎亚,將內(nèi)存劃分為若干個不同的區(qū)域员寇。一般情況下將堆分為老年代和新生代,方法區(qū)為永生代(新版本將永生代廢棄第美,引入元空間的概念蝶锋,永生代使用Jvm內(nèi)存兒元空間直接使用物理內(nèi)存)。新生代分為Eden區(qū)和Survivor區(qū)(Survivor from和Survivor to)什往,大小比例默認為8:1:1.新產(chǎn)生的對象優(yōu)先進入Eden區(qū)扳缕,當(dāng)Eden區(qū)滿了之后再使用Survivor from,當(dāng)Survivor from也滿了之后别威,就進行Minor GC(新生代GC)躯舔,將Eden和Survivor from中存活的對象使用Copying算法復(fù)制進入Survivor to,原來的Survivor to就成了新的Survivor from省古,Copying算法在復(fù)制之后清空Eden和Survivor from粥庄,原來的Survivor from就成了新的Survivor to。復(fù)制的時候豺妓,如果Survivor to無法容納全部存活的對象惜互,則根據(jù)老年代的分配擔(dān)保,將對象復(fù)制進入老年代琳拭,如果老年代也無法容納训堆,則進行Full GC(老年代GC或者稱為Major GC)。老年代的特點就是每次垃圾收集時白嘁,只有少量對象需要被回收坑鱼,而新生代的特點是每次都要回收大量的對象,因此可以根據(jù)不同代的特點采取合理的收集算法权薯。程序中主動調(diào)用System.gc()強制執(zhí)行的GC為Full GC姑躲。
Jvm對新生代采用Copying算法,因為新生代每次GC都要回收大部分對象盟蚣,需要復(fù)制的操作次數(shù)較少黍析;
老年代的特點是每次GC只回收少量對象,一般使用Mark-Compact算法屎开;
1)大對象直接進入老年代阐枣,Jvm有個參數(shù)配置,大于這個值直接進入老年代,避免Eden和Survivor區(qū)之間發(fā)生大量的對象復(fù)制操作蔼两。
2)長期存活的對象進入老年代甩鳄,Jvm給每個對象定義一個對象年齡計數(shù)器,如果對象在Eden出生额划,經(jīng)歷一次Minor GC之后仍存活妙啃,將其移入Survivor區(qū)并且年齡+1.每經(jīng)過一次GC年齡+1,當(dāng)年齡到達15(Jvm參數(shù),默認為15)俊戳,移入老年代揖赴。
3)但是Jvm不是永遠要求年齡必須達到最大年齡才可以晉升老年代,如果Survivor空間中相同年齡(如年齡X)的所有對象大小的總和大于Survivor的一半時抑胎,年齡大于等于X的所有對象直接進入老年代燥滑。
簡單的三個收集算法
1)標(biāo)記清除算法:
分標(biāo)記,清除兩個階段阿逃。首先標(biāo)記所需要回收的對象铭拧,在標(biāo)記完成之后統(tǒng)一回收所有被標(biāo)記的對象。不足:一個效率問題恃锉,標(biāo)記和清除的效率都不高搀菩;一個空間問題,標(biāo)記清除之后產(chǎn)生了大量不連續(xù)的內(nèi)存碎片,碎片太多導(dǎo)致需要分配大對象時無法找到足夠的連續(xù)內(nèi)存而不得不再觸發(fā)一次GC淡喜。
2)復(fù)制算法Copying:
為了解決效率問題秕磷,復(fù)制算法將可用的內(nèi)存分為兩部分诵闭,每次只使用其中一塊炼团,當(dāng)一塊內(nèi)存用完了,將還存活的對象復(fù)制到另一塊上面疏尿,然后再把剛剛用過的內(nèi)存空間一次性清理掉瘟芝,這樣解決了碎片問題。
3)標(biāo)記整理算法 Mark-Compact:
復(fù)制算法在對象存活率較高時就會頻繁進行復(fù)制操作褥琐,效率將降低锌俱,因此有了Mark-Compact算法。標(biāo)記過程和標(biāo)記清除算法相同敌呈,但是后續(xù)不是直接清除對象贸宏,而是讓所有存活的對象向同一側(cè)移動,然后直接清理邊界以外的內(nèi)存磕洪。
兩種算法判定對象是否存活
1)引用計數(shù)算法:給對象中添加一個引用計數(shù)器吭练,每當(dāng)一個地方應(yīng)用了對象,計數(shù)器+1析显,當(dāng)引用失效鲫咽,計數(shù)器-1.計數(shù)器為0表示該對象已死,可回收。但是這個方法很難解決兩個對象循環(huán)相互引用的情況分尸。
2)可大型分析算法:通過一系列稱為“GC Roots”的對象作為起點锦聊,從這些節(jié)點開始向下搜索,搜索所走過的路徑稱為引用鏈箩绍,當(dāng)一個對象到GC Roots沒有任何引用鏈相連(即對象到GC Roots不可達)孔庭,則證明對象已死,可回收材蛛。Java中可以作為GC Roots的對象包括:Jvm棧中引用的對象史飞,本地方法棧中Native方法引用的對象,方法區(qū)靜態(tài)屬性引用的對象仰税,方法區(qū)常量引用的對象构资。主流實現(xiàn)中,都是通過可達性分析算法來判定對象是否存活陨簇。