論壇建站哪個(gè)比較好廣點(diǎn)通投放平臺(tái)
參考:JVM學(xué)習(xí)筆記(一)_卷心菜不卷Iris的博客-CSDN博客
GC垃圾回收
面試題:
JVM內(nèi)存模型以及分區(qū),需要詳細(xì)到每個(gè)區(qū)放什么
堆里面的分區(qū):Eden,survival from to,老年代,各自的特點(diǎn)。
GC的三種收集方法:標(biāo)記清除、標(biāo)記整理、復(fù)制算法的原理與特點(diǎn),分別用在什么地方
針對(duì)RockitMQ 消息中間件的服務(wù)器,應(yīng)該使用什么樣的GC算法?(TODO)
Minor GC與Full GC分別在什么時(shí)候發(fā)生
GC發(fā)生的區(qū)域:方法區(qū) 和 堆
?
JVM垃圾判定算法:(對(duì)象已死?)
引用計(jì)數(shù)法(Reference-Counting)
可達(dá)性分析算法(根搜索算法)
垃圾判定
4.2.1. 引用計(jì)數(shù)法(Reference-Counting)
引用計(jì)數(shù)算法是通過判斷對(duì)象的引用數(shù)量來決定對(duì)象是否可以被回收。
給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。
優(yōu)點(diǎn):
簡(jiǎn)單,高效,現(xiàn)在的objective-c、python等用的就是這種算法。
缺點(diǎn):
引用和去引用伴隨著加減算法,影響性能
很難處理循環(huán)引用,相互引用的兩個(gè)對(duì)象則無法釋放。
因此目前主流的Java虛擬機(jī)都摒棄掉了這種算法。
?
可達(dá)性分析算法
這個(gè)算法的基本思想就是通過一系列的稱為?“GC Roots”?的對(duì)象作為起點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,節(jié)點(diǎn)所走過的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到 GC Roots 沒有任何引用鏈相連的話,則證明此對(duì)象是不可用的。
在Java語言中,可以作為GC Roots的對(duì)象包括下面幾種:
虛擬機(jī)棧(棧幀中的本地變量表)中的引用對(duì)象。
方法區(qū)中的類靜態(tài)屬性引用的對(duì)象。
方法區(qū)中的常量引用的對(duì)象。
本地方法棧中JNI(Native方法)的引用對(duì)象
真正標(biāo)記以為對(duì)象為可回收狀態(tài)至少要標(biāo)記兩次。
第一次標(biāo)記:不在 GC Roots 鏈中,標(biāo)記為可回收對(duì)象。
第二次標(biāo)記:判斷當(dāng)前對(duì)象是否實(shí)現(xiàn)了finalize() 方法,如果沒有實(shí)現(xiàn)則直接判定這個(gè)對(duì)象可以回收,如果實(shí)現(xiàn)了就會(huì)先放入一個(gè)隊(duì)列中。并由虛擬機(jī)建立一個(gè)低優(yōu)先級(jí)的程序去執(zhí)行它,隨后就會(huì)進(jìn)行第二次小規(guī)模標(biāo)記,在這次被標(biāo)記的對(duì)象就會(huì)真正被回收了!
四種引用
平時(shí)只會(huì)用到強(qiáng)引用和軟引用。
強(qiáng)引用:
? 類似于 Object obj = new Object(); 只要強(qiáng)引用還存在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
軟引用:
? SoftReference 類實(shí)現(xiàn)軟引用。在系統(tǒng)要發(fā)生內(nèi)存溢出異常之前,才會(huì)將這些對(duì)象列進(jìn)回收范圍之中進(jìn)行二次回收。如果這次回收還沒有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常。軟引用可用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存。
弱引用:
? WeakReference 類實(shí)現(xiàn)弱引用。對(duì)象只能生存到下一次垃圾收集之前。在垃圾收集器工作時(shí),無論內(nèi)存是否足夠都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。
虛引用:
? PhantomReference 類實(shí)現(xiàn)虛引用。無法通過虛引用獲取一個(gè)對(duì)象的實(shí)例,為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。
作用:
虛引用主要用來跟蹤對(duì)象被垃圾回收器回收的活動(dòng)。虛引用與軟引用和弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前,把這個(gè)虛引用加入到與之 關(guān)聯(lián)的引用隊(duì)列中。你聲明虛引用的時(shí)候是要傳入一個(gè)queue的。當(dāng)你的虛引用所引用的對(duì)象已經(jīng)執(zhí)行完finalize函數(shù)的時(shí)候,就會(huì)把對(duì)象加到queue里面。你可以通過判斷queue里面是不是有對(duì)象來判斷你的對(duì)象是不是要被回收了
?
GC垃圾回收主要有四大算法:(怎么找到已死對(duì)象并清除?)
復(fù)制算法(Copying)
標(biāo)記清除(Mark-Sweep)
標(biāo)記壓縮(Mark-Compact),又稱標(biāo)記整理
分代收集算法(Generational-Collection)
GC的特點(diǎn):
- 次數(shù)上頻繁收集Young區(qū)
- 次數(shù)上較少收集Old區(qū)
- 基本不動(dòng)Perm區(qū)
垃圾回收算法
在介紹JVM垃圾回收算法前,先介紹一個(gè)概念:Stop-the-World
Stop-the-world意味著 JVM由于要執(zhí)行GC而停止了應(yīng)用程序的執(zhí)行,并且這種情形會(huì)在任何一種GC算法中發(fā)生。當(dāng)Stop-the-world發(fā)生時(shí),除了GC所需的線程以外,所有線程都處于等待狀態(tài)直到GC任務(wù)完成。事實(shí)上,GC優(yōu)化很多時(shí)候就是指減少Stop-the-world發(fā)生的時(shí)間,從而使系統(tǒng)具有高吞吐 、低停頓的特點(diǎn)。
1. 復(fù)制算法(Copying)
該算法將內(nèi)存平均分成兩部分,然后每次只使用其中的一部分,當(dāng)這部分內(nèi)存滿的時(shí)候,將內(nèi)存中所有存活的對(duì)象復(fù)制到另一個(gè)內(nèi)存中,然后將之前的內(nèi)存清空,只使用這部分內(nèi)存,循環(huán)下去。

優(yōu)點(diǎn):
實(shí)現(xiàn)簡(jiǎn)單
不產(chǎn)生內(nèi)存碎片
缺點(diǎn):
將內(nèi)存縮小為原來的一半,浪費(fèi)了一半的內(nèi)存空間,代價(jià)太高;如果不想浪費(fèi)一半的空間,就需要有額外的空間進(jìn)行分配擔(dān)保,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法。
如果對(duì)象的存活率很高,我們可以極端一點(diǎn),假設(shè)是100%存活,那么我們需要將所有對(duì)象都復(fù)制一遍,并將所有引用地址重置一遍。復(fù)制這一工作所花費(fèi)的時(shí)間,在對(duì)象存活率達(dá)到一定程度時(shí),將會(huì)變的不可忽視。 所以從以上描述不難看出,復(fù)制算法要想使用,最起碼對(duì)象的存活率要非常低才行,而且最重要的是,我們必須要克服50%內(nèi)存的浪費(fèi)。
年輕代中使用的是Minor GC,這種GC算法采用的是復(fù)制算法(Copying)。
? HotSpot JVM把年輕代分為了三部分:1個(gè)Eden區(qū)和2個(gè)Survivor區(qū)(分別叫from和to)。默認(rèn)比例為8:1:1,一般情況下,新創(chuàng)建的對(duì)象都會(huì)被分配到Eden區(qū)。因?yàn)槟贻p代中的對(duì)象基本都是朝生夕死的(90%以上),所以在年輕代的垃圾回收算法使用的是復(fù)制算法。
? 在GC開始的時(shí)候,對(duì)象只會(huì)存在于Eden區(qū)和名為“From”的Survivor區(qū),Survivor區(qū)“To”是空的。緊接著進(jìn)行GC,Eden區(qū)中所有存活的對(duì)象都會(huì)被復(fù)制到“To”,而在“From”區(qū)中,仍存活的對(duì)象會(huì)根據(jù)他們的年齡值來決定去向。對(duì)象在Survivor區(qū)中每熬過一次Minor GC,年齡就會(huì)增加1歲。年齡達(dá)到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設(shè)置)的對(duì)象會(huì)被移動(dòng)到年老代中,沒有達(dá)到閾值的對(duì)象會(huì)被復(fù)制到“To”區(qū)域。經(jīng)過這次GC后,Eden區(qū)和From區(qū)已經(jīng)被清空。這個(gè)時(shí)候,“From”和“To”會(huì)交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會(huì)保證名為To的Survivor區(qū)域是空的。Minor GC會(huì)一直重復(fù)這樣的過程,直到“To”區(qū)被填滿,“To”區(qū)被填滿之后,會(huì)將所有對(duì)象移動(dòng)到年老代中。
?
因?yàn)镋den區(qū)對(duì)象一般存活率較低,一般的,使用兩塊10%的內(nèi)存作為空閑和活動(dòng)區(qū)間,而另外80%的內(nèi)存,則是用來給新建對(duì)象分配內(nèi)存的。一旦發(fā)生GC,將10%的from活動(dòng)區(qū)間與另外80%中存活的eden對(duì)象轉(zhuǎn)移到10%的to空閑區(qū)間,接下來,將之前90%的內(nèi)存全部釋放,以此類推。
2.標(biāo)記清除(Mark-Sweep)
“標(biāo)記-清除”(Mark Sweep)算法是幾種GC算法中最基礎(chǔ)的算法,是因?yàn)楹罄m(xù)的收集算法都是基于這種思路并對(duì)其不足進(jìn)行改進(jìn)而得到的。正如名字一樣,算法分為2個(gè)階段:
標(biāo)記出需要回收的對(duì)象,使用的標(biāo)記算法均為可達(dá)性分析算法。
回收被標(biāo)記的對(duì)象。
缺點(diǎn):
-
效率問題(兩次遍歷)
-
空間問題(標(biāo)記清除后會(huì)產(chǎn)生大量不連續(xù)的碎片。JVM就不得不維持一個(gè)內(nèi)存的空閑列表,這又是一種開銷。而且在分配數(shù)組對(duì)象的時(shí)候,尋找連續(xù)的內(nèi)存空間會(huì)不太好找。)
3. 標(biāo)記壓縮(Mark-Compact)
標(biāo)記-整理法是標(biāo)記-清除法的一個(gè)改進(jìn)版。同樣,在標(biāo)記階段,該算法也將所有對(duì)象標(biāo)記為存活和死亡兩種狀態(tài);不同的是,在第二個(gè)階段,該算法并沒有直接對(duì)死亡的對(duì)象進(jìn)行清理,而是通過所有存活對(duì)像都向一端移動(dòng),然后直接清除邊界以外的內(nèi)存。
優(yōu)點(diǎn):
? 標(biāo)記/整理算法不僅可以彌補(bǔ)標(biāo)記/清除算法當(dāng)中,內(nèi)存區(qū)域分散的缺點(diǎn),也消除了復(fù)制算法當(dāng)中,內(nèi)存減半的高額代價(jià)。
缺點(diǎn):
? 如果存活的對(duì)象過多,整理階段將會(huì)執(zhí)行較多復(fù)制操作,導(dǎo)致算法效率降低。
老年代一般是由標(biāo)記清除或者是標(biāo)記清除與標(biāo)記整理的混合實(shí)現(xiàn)。
?
4. 分代收集算法(Generational-Collection)
內(nèi)存效率:復(fù)制算法>標(biāo)記清除算法>標(biāo)記整理算法(此處的效率只是簡(jiǎn)單的對(duì)比時(shí)間復(fù)雜度,實(shí)際情況不一定如此)。
內(nèi)存整齊度:復(fù)制算法=標(biāo)記整理算法>標(biāo)記清除算法。
內(nèi)存利用率:標(biāo)記整理算法=標(biāo)記清除算法>復(fù)制算法。
可以看出,效率上來說,復(fù)制算法是當(dāng)之無愧的老大,但是卻浪費(fèi)了太多內(nèi)存,而為了盡量兼顧上面所提到的三個(gè)指標(biāo),標(biāo)記/整理算法相對(duì)來說更平滑一些,但效率上依然不盡如人意,它比復(fù)制算法多了一個(gè)標(biāo)記的階段,又比標(biāo)記/清除多了一個(gè)整理內(nèi)存的過程
難道就沒有一種最優(yōu)算法嗎?
回答:無,沒有最好的算法,只有最合適的算法。==========>分代收集算法。
分代回收算法實(shí)際上是把復(fù)制算法和標(biāo)記整理法的結(jié)合,并不是真正一個(gè)新的算法,一般分為:老年代(Old Generation)和新生代(Young Generation),老年代就是很少垃圾需要進(jìn)行回收的,新生代就是有很多的內(nèi)存空間需要回收,所以不同代就采用不同的回收算法,以此來達(dá)到高效的回收算法。
年輕代(Young Gen)
? 年輕代特點(diǎn)是區(qū)域相對(duì)老年代較小,對(duì)像存活率低。
? 這種情況復(fù)制算法的回收整理,速度是最快的。復(fù)制算法的效率只和當(dāng)前存活對(duì)像大小有關(guān),因而很適用于年輕代的回收。而復(fù)制算法內(nèi)存利用率不高的問題,通過hotspot中的兩個(gè)survivor的設(shè)計(jì)得到緩解。
老年代(Tenure Gen)
? 老年代的特點(diǎn)是區(qū)域較大,對(duì)像存活率高。
? 這種情況,存在大量存活率高的對(duì)像,復(fù)制算法明顯變得不合適。一般是由標(biāo)記清除或者是標(biāo)記清除與標(biāo)記整理的混合實(shí)現(xiàn)。
?
?