Java技術體系中所提倡的自動內存管理策略最終能夠歸結爲自動化地解決了兩個問題:給對象分配內存以及回收分配給對象的內存;算法
幾條廣泛的分配規則:
一、對象優先在Eden區分配
年輕代分爲三個區:1個Eden區+2個Survivor區。
大部分對象在Eden區中生成(大對象能夠直接被建立在年老代),還存活的對象將被複制到一個Survivor區,當這個Survivor區滿時,此區的存活對象將被複制到剩下的一個Survivor區中,當這個Survivor區也滿了的時候,從第一個Survivor複製過來的而且此時還存活的對象,將被複制到年老區。
須要注意的是,Survivor的兩個區是對稱的,沒前後關係,因此同一個區中可能同時存在從Eden區複製過來的對象和從前一個Survivor區複製過來的對象,而複製到年老區的就只有從第一個Survivor區過去的對象。而且Survivor區總有一個是空的。
Minor GC(Young GC):對象被建立時,內存的分配首先發生在年輕代,大部分的對象在建立後很快就再也不使用,所以很快變得不可達,因而被年輕代的GC機制清理掉,這個GC機制被稱爲Minor GC或Young GC。
注意Minor GC並不表明年輕代內存不足,它事實上只表示在Eden區上的GC。
因爲絕大部分對象都是短命的,甚至存活不到Survivor區中,因此Eden與Survivor的比例較大,HotSpot默認爲8:1.數組
在Eden區,HotSpot虛擬機使用了兩種技術來加快內存分配。分別是bump-the-pointer和TLAB(Thread- Local Allocation Buffers),這兩種技術的作法分別是:因爲Eden區是連續的,所以bump-the-pointer技術的核心就是跟蹤最後建立的一個對象,在對象建立時,只須要檢查最後一個對象後面是否有足夠的內存便可,從而大大加快內存分配速度;而對於TLAB技術是對於多線程而言的,將Eden區分爲若干段,每一個線程使用獨立的一段,避免相互影響。TLAB結合bump-the-pointer技術,將保證每一個線程都使用Eden區的一段,並快速的分配內存;安全
二、大對象直接分配在老年代
所謂的大對象是指的須要大量連續內存空間的Java對象。好比:那種很長的字符串以及數組。
常常出現大對象容易致使內存還有很多空間時就提早觸發垃圾收集以獲取足夠的連續空間來「安置」它們;
年老代存放從年輕代存活的對象。通常來講年老代存放的都是生命週期較長的對象。
年老代的空間通常比年輕代大,能存放更多的對象,在年老代上發生的GC次數也比年輕代少。
當年老代內存不足時,將執行Major GC,也叫Full GC;
可能存在年老代對象引用新生代對象的狀況,若是須要執行Young GC,則可能須要查詢整個老年代以肯定是否能夠清理回收,這顯然是低效的。解決的方法是,年老代中維護一個512 byte的塊——」card table「,全部老年代對象引用新生代對象的記錄都記錄在這裏。Young GC時,只要查這裏便可,不用再去查所有老年代,所以性能大大提升。
通常,老年代用的算法是標記-整理算法,即:標記出仍然存活的對象(存在引用的),將全部存活的對象向一端移動,以保證內存的連續;多線程
在發生Minor GC時,虛擬機會檢查每次晉升進入老年代的大小是否大於老年代的剩餘空間大小,若是大於,則直接觸發一次Full GC,不然,就查看是否設置了-XX:+HandlePromotionFailure(容許擔保失敗),若是容許,則只會進行MinorGC,此時能夠容忍內存分配失敗;若是不容許,則仍然進行Full GC(這表明着若是設置-XX:+Handle PromotionFailure,則觸發MinorGC就會同時觸發Full GC,哪怕老年代還有不少內存,因此,最好不要這樣作)。
使用-XX:PretenureSizeThreshold參數,令大於這個設置值的對象直接在老年代分配;這樣的目的主要是爲了不在Eden區以及2個Survivor區之間發生大量的內存複製;
-XX:PretenureSizeThreshold參數只對Serial 和ParNew 收集器有效,Parallel Sacvenge收集器不認識此參數。
-XX:PretenureSizeThreshold參數的值不能像-Xms同樣直接寫3M要寫成3145728;性能
三、長時間存活的對象分配在老年代
虛擬機採用了分代收集的思想來管理內存,那麼內存回收時就必須能識別哪些對象在新生代,哪些對象應在老年代,因此,虛擬機給每一個對象定義了一個對象年齡計數器;
若是對象在Eden區出生並經歷一次Minor GC後仍然存活,而且能被Survivor區所容納,那麼對象年齡計數器值爲1;
對象在Survivor區中每熬過一次Minor GC,年齡就會增長1;
默認年齡是15,能夠經過設置-XX:MaxTenuringThreshold來設置。spa
四、動態對象年齡斷定
爲了能更好的適應不一樣程序的內存情況,虛擬機並非永遠都是要求對象的年齡達到了MaxTenuringThreshold才能晉升老年代;
若是在Survivor空間內相同年齡全部對象大小總和大於 Survivor空間的一半,年齡等於或大於該年齡的對象能夠直接進入老年代,而無需達到MaxTenuringThreshold設定的年齡;線程
五、空間分配擔保
在發生Minor GC以前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代全部對象的總和。若是條件成立,那麼Minor GC能夠確保是安全的;
若是不成立,那麼虛擬機會查看HandlerPromotionFailure設置值是否容許擔保失敗。
若是容許,會檢查老年代最大可 用的連續空間是否大於歷次晉升到老年代對象的平均大小,若是大於,則嘗試進行一次Minor GC;若是小於,則會進行一次Full GC對象