摘要:復制這一工作所花費的時間,在對象存活率達到一定程度時,將會變的不可忽視。針對老年代老年代的特點是區(qū)域較大,對像存活率高。這種情況,存在大量存活率高的對像,復制算法明顯變得不合適。
GC(Garbage Collection)即Java垃圾回收機制,是Java與C++的主要區(qū)別之一,作為Java開發(fā)者,一般不需要專門編寫內(nèi)存回收和垃圾清理代碼,對內(nèi)存泄露和溢出的問題,也不需要像C++程序員那樣戰(zhàn)戰(zhàn)兢兢,就是因為Java有這個方便的機制。
為了對GC有一個直觀的認識,先來一張圖:
對圖中各種名詞不熟悉的話,請參照我的上一篇文章:JVM小結(jié)
JVM在進行GC時,并非每次都對上面三個內(nèi)存區(qū)域一起回收的,大部分時候回收的都是指新生代。因此GC按照回收的區(qū)域又分了兩種類型,一種是普通GC(minor GC),一種是全局GC(major GC or Full GC)
普通GC(minor GC):只針對新生代區(qū)域的GC。
全局GC(major GC or Full GC):針對年老代的GC,偶爾伴隨對新生代的GC以及對永久代的GC。
四大算法 1. 復制算法(Copying)年輕代中使用的是Minor GC,這種GC算法采用的是復制算法(Copying)。
此圖代表了堆的內(nèi)存結(jié)構(gòu)
HotSpot JVM把年輕代分為了三部分:1個Eden區(qū)和2個Survivor區(qū)(分別叫from和to)。默認比例為8:1:1,一般情況下,新創(chuàng)建的對象都會被分配到Eden區(qū)(一些大對象特殊處理),這些對象經(jīng)過第一次Minor GC后,如果仍然存活,將會被移到Survivor區(qū)。對象在Survivor區(qū)中每熬過一次Minor GC,年齡就會增加1歲,當它的年齡增加到一定程度時,就會被移動到年老代中。因為年輕代中的對象基本都是朝生夕死的(80%以上),所以在年輕代的垃圾回收算法使用的是復制算法,復制算法的基本思想就是將內(nèi)存分為兩塊,每次只用其中一塊,當這一塊內(nèi)存用完,就將還活著的對象復制到另外一塊上面。復制算法不會產(chǎn)生內(nèi)存碎片。
在GC開始的時候,對象只會存在于Eden區(qū)和名為From的Survivor區(qū),Survivor區(qū)To是空的。緊接著進行GC,Eden區(qū)中所有存活的對象都會被復制到To,而在From區(qū)中,仍存活的對象會根據(jù)他們的年齡值來決定去向。年齡達到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設置)的對象會被移動到年老代中,沒有達到閾值的對象會被復制到To區(qū)域。經(jīng)過這次GC后,Eden區(qū)和From區(qū)已經(jīng)被清空。這個時候,From和To會交換他們的角色,也就是新的To就是上次GC前的From,新的From就是上次GC前的To。不管怎樣,都會保證名為To的Survivor區(qū)域是空的。Minor GC會一直重復這樣的過程,直到To區(qū)被填滿,To區(qū)被填滿之后,會將所有對象移動到年老代中。
-XX:MaxTenuringThreshold 設置對象在新生代中存活的次數(shù)
因為Eden區(qū)對象一般存活率較低,一般的,使用兩塊10%的內(nèi)存作為空閑和活動區(qū)間,而另外80%的內(nèi)存,則是用來給新建對象分配內(nèi)存的。一旦發(fā)生GC,將10%的from活動區(qū)間與另外80%中存活的eden對象轉(zhuǎn)移到10%的to空閑區(qū)間,接下來,將之前90%的內(nèi)存全部釋放,以此類推。
劣勢:
復制算法彌補了標記/清除算法中,內(nèi)存布局混亂的缺點。不過與此同時,它的缺點也是相當明顯的:
它浪費了一半的內(nèi)存。
如果對象的存活率很高,我們可以極端一點,假設是100%存活,那么我們需要將所有對象都復制一遍,并將所有引用地址重置一遍。復制這一工作所花費的時間,在對象存活率達到一定程度時,將會變的不可忽視。 所以從以上描述不難看出,復制算法要想使用,最起碼對象的存活率要非常低才行,而且最重要的是,我們必須要克服50%內(nèi)存的浪費。
2. 標記清除(Mark-Sweep)老年代一般是由標記清除或者是標記清除與標記整理的混合實現(xiàn)。
當堆中的有效內(nèi)存空間(available memory)被耗盡的時候,就會停止整個程序(也被稱為stop the world),然后進行兩項工作,第一項則是標記,第二項則是清除。
標記:從引用根節(jié)點開始標記所有被引用的對象。標記的過程其實就是遍歷所有的GC Roots,然后將所有GC Roots可達的對象 標記為存活的對象。
清除:遍歷整個堆,把未標記的對象清除。
通俗來講,就是當程序運行期間,若可以使用的內(nèi)存被耗盡的時候,GC線程就會被觸發(fā)并將程序暫停,隨后將依舊存活的對象標記一遍,最終再將堆中所有沒被標記的對象全部清除掉,接下來便讓程序恢復運行。
缺點:
效率比較低(遞歸與全堆對象遍歷),而且在進行GC的時候,需要停止應用程序,這會導致用戶體驗非常差。
這種方式清理出來的空閑內(nèi)存是不連續(xù)的,我們的死亡對象都是隨即的出現(xiàn)在內(nèi)存的各個角落的,把它們清除之后,內(nèi)存的布局自然會散亂。而為了應付這一點,JVM就不得不維持一個內(nèi)存的空閑列表,這又是一種開銷。而且在分配數(shù)組對象的時候,尋找連續(xù)的內(nèi)存空間會有難度。
3. 標記壓縮(Mark-Compact)老年代一般是由標記清除或者是標記清除與標記壓縮的混合實現(xiàn)。
在整理壓縮階段,不再對標記的對像做回收,而是通過所有存活對像都向一端移動,然后直接清除邊界以外的內(nèi)存。
可以看到,標記的存活對象將會被整理,按照內(nèi)存地址依次排列,而未被標記的內(nèi)存會被清理掉。如此一來,當我們需要給新對象分配內(nèi)存時,JVM只需要持有一個內(nèi)存的起始地址即可,這比維護一個空閑列表顯然少了許多開銷。
標記/整理算法不僅可以彌補標記/清除算法當中,內(nèi)存區(qū)域分散的缺點,也消除了復制算法當中,內(nèi)存減半的高額代價。
劣勢:標記/整理算法唯一的缺點就是效率也不高,不僅要標記所有存活對象,還要整理所有存活對象的引用地址。從效率上來說,標記/整理算法要低于復制算法。
4. 標記清除壓縮(Mark-Sweep-Compact) 多提一嘴:引用計數(shù)法這種算法最直接簡單,它維護了一個引用計數(shù)器,對象被引用一次計數(shù)器+1,少一次-1,如果計數(shù)器為0則對象就被視為垃圾進行回收。
注:JVM的實現(xiàn)一般不采用這種方式。
劣勢:
每次對對象賦值時均需維護計數(shù)器,且計數(shù)器本身有一定消耗。
較難處理循環(huán)引用。
小結(jié)內(nèi)存效率:復制算法>標記清除算法>標記整理算法(此處的效率只是簡單的對比時間復雜度,實際情況不一定如此)。
內(nèi)存整齊度:復制算法==標記整理算法>標記清除算法。
內(nèi)存利用率:標記整理算法==標記清除算法>復制算法。
可以看出,效率上來說,復制算法最快,但是卻浪費了太多內(nèi)存,而為了盡量兼顧上面所提到的三個指標,標記/整理算法相對來說更平滑一些,但效率上依然不盡如人意,它比復制算法多了一個標記的階段,又比標記/清除多了一個整理內(nèi)存的過程。
有沒有最好的算法呢?只能說:沒有最好的,只有最適合的——分代收集:
針對年輕代年輕代特點是區(qū)域相對老年代較小,對像存活率低。這種情況復制算法的回收整理,速度是最快的。復制算法的效率只和當前存活對像大小有關(guān),因而很適用于年輕代的回收。而復制算法內(nèi)存利用率不高的問題,通過hotspot中的兩個survivor的設計得到緩解。
針對老年代老年代的特點是區(qū)域較大,對像存活率高。
這種情況,存在大量存活率高的對像,復制算法明顯變得不合適。一般是由標記清除或者是標記清除與標記整理的混合實現(xiàn)。
Mark階段的開銷與存活對像的數(shù)量成正比,這點上說來,對于老年代,標記清除或者標記整理有一些不符,但可以通過多核/線程利用,對并發(fā)、并行的形式提標記效率。
Sweep階段的開銷與所管理區(qū)域的大小形正相關(guān),但Sweep“就地處決”的特點,回收的過程沒有對像的移動。使其相對其它有對像移動步驟的回收算法,仍然是效率最好的。但是需要解決內(nèi)存碎片問題。
Compact階段的開銷與存活對像的數(shù)據(jù)成開比,如上一條所描述,對于大量對像的移動是很大開銷的,做為老年代的第一選擇并不合適。
基于上面的考慮,老年代一般是由標記清除或者是標記清除與標記整理的混合實現(xiàn)。以hotspot中的CMS回收器為例,CMS是基于Mark-Sweep實現(xiàn)的,對于對像的回收效率很高,而對于碎片問題,CMS采用基于Mark-Compact算法的Serial Old回收器做為補償措施:當內(nèi)存回收不佳(碎片導致的Concurrent Mode Failure時),將采用Serial Old執(zhí)行Full GC以達到對老年代內(nèi)存的整理。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/68363.html
摘要:序本主要研究一下的在進行的都采用了的技術(shù)面向的垃圾收集器,它的主要有包括這個階段用到了進行包括在進行的時候采用了的技術(shù)全稱為,其要點如下的過程就是遍歷標記,采用的是三色標記算法,這三種顏色為表示還未訪問到訪問到但是它用到的引用還沒 序 本主要研究一下Garbage Collector的SATB CMS、G1、Shenandoah在進行concurrent marking的都采用了SAT...
摘要:當時,如果老生區(qū)大小超過設定的值時,就會報錯。一般是無限制增長的數(shù)組無限制設置屬性和值大循環(huán)等出處林小新。這部分由于攻城獅并為深入,可以參考如何定位的內(nèi)存泄漏內(nèi)存泄漏以及定位 showImg(https://segmentfault.com/img/bVbnysD?w=649&h=658);↑開局一張圖,故事全靠編↑ 從一次宕機說起 這是一個很狗血的故事,故事的開頭是一個項目,這個項...
摘要:一個對象若只被弱引用所引用,則被認為是不可訪問或弱可訪問的,并因此可能在任何時刻被回收。也就是說,一旦不再需要,里面的鍵名對象和所對應的鍵值對會自動消失,不用手動刪除引用。如果有錯誤或者不嚴謹?shù)牡胤剑垊毡亟o予指正,十分感謝。 前言 我們先從 WeakMap 的特性說起,然后聊聊 WeakMap 的一些應用場景。 特性 1. WeakMap 只接受對象作為鍵名 const map = ...
閱讀 3289·2023-04-26 02:40
閱讀 4639·2021-09-22 15:22
閱讀 1573·2021-09-22 10:02
閱讀 3474·2021-08-11 10:23
閱讀 1388·2019-08-30 15:55
閱讀 2487·2019-08-30 12:48
閱讀 584·2019-08-30 11:04
閱讀 697·2019-08-29 16:29