05-堆內存分代


堆內存詳解

理解一下,爲何要對堆內存分代?固然,不分代也能完成它所作的事情,之因此分代,實際上是爲了優化GC性能。算法

若是沒有分代,那麼全部的對象都會放在一塊內存區域中,GC的時候尋找垃圾對象,就須要對整個內存區域進行掃描,這樣會很大程度上影響GC效率,在Java中,不少對象都是 「朝生夕死」 的,若是把內存空間劃分區域的話,將新建立的對象放到某個區域中,GC的時候優先回收這部分 「朝生夕死」 的對象,這樣就會騰出很大的空間來。jvm

因此就對堆內存進行了分代,下面這個圖就是堆內存的分佈圖性能


image.png


堆內存被劃分爲兩塊,分別是年輕代老年代優化

年輕代

年輕代其實分爲兩部分,分別是1個Eden區和2個Survivor區(分別叫from和to),默認比例是8:1:1,通常狀況下,新建立的對象基本都會放到Eden區,(除非一些特別大的對象會直接放到老年代),當Eden沒有足夠的空間的時候,就會觸發jvm發起一次Minor GC,若是對象通過一次Minor GC還存活,而且又能被Survivor空間接受,那麼將被移動到Survivor空間當中,對象在Survivor區中每熬過一次Minor GC,年齡就會增長一歲,當它的年齡增長到必定程度(默認15歲)時,就會被移到老年代中,固然晉升老年代的年齡是能夠設置的。spa

複製整理算法

由於年輕代中的對象基本都是朝生夕死的(80%以上),因此在年輕代的垃圾回收算法使用的是複製整理算法,複製整理算法的基本思想就是將內存分爲兩塊,每次只用其中一塊,當這一塊內存用完,就將還活着的對象複製到另一塊上面。對象

優勢:不會產生內存碎片
缺點:會開闢新的空間,也就是To survivor,用來保存有用對象
複製對象會花費一些時間

在GC開始的時候,對象只會存在於Eden區和名爲「From」的Survivor區,Survivor區的「To」是空的。緊接着進行GC,通過一輪Minor GC後,Eden區中全部存活的對象都會被複制到「To」,而在「From」區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到必定值(年齡閾值,能夠經過-XX:MaxTenuringThreshold來設置)的對象會被移動到年老代中,沒有達到閾值的對象會被複制到「To」區域。通過此次GC後,Eden區和From區已經被清空。這個時候,「From」和「To」會交換他們的角色,也就是新的「To」就是上次GC前的「From」,新的「From」就是上次GC前的「To」。無論怎樣,都會保證名爲To的Survivor區域是空的。Minor GC會一直重複這樣的過程,直到「To」區被填滿,「To」區被填滿以後,會將全部對象移動到年老代中。blog

老年代

當年輕帶隨着不斷地Minor GC ,from survivor中的對象會不斷成長,當from survivor中的對象成長大15歲的時候,就會進入老年代,隨着Minor GC的持續進行,老年代中對象也會持續增加,最終老年代的空間也會不夠用,此時就會執行老年代的GC-->Major GC。Major GC使用的算法是標記清除算法或者標記-壓縮算法。內存

標記清除

步驟it

【1】首先會去根對象的集合中進行遍歷,發現對象還存在引用,就是存活的對象並打上一個存活的標記
【2】再去根對象集合進行二次遍歷,將沒有被打上標記的對象清除掉。

優缺點io

優勢:可以進入老年代的對象,通常都相對穩定,被回收的數量較少,減小對磁盤的清理,若是採用複製整理算法,被複制的對象會有不少。
缺點:雖然垃圾獲得了回收,可是回收之後,堆內存中出現了不連續的現狀---內存碎片,致使大對象沒法建立

標記壓縮

和標記清除算法基本相同,惟一不一樣的就是,在清除完成以後,會把存活的對象向內存的一邊進行壓縮,這樣就能夠解決內存碎片問題。上篇文章已經詳細介紹過了,這裏就再也不贅述了。

堆內存常見的參數配置

【1】-XX:NewSize和-XX:MaxNewSize 用於設置年輕代的大小,建議設爲整個堆大小的1/3或者1/4,兩個值設爲同樣大。 【2】-XX:SurvivorRatio 用於設置Eden和其中一個Survivor的比值,這個值也比較重要。 【3】-XX:+PrintTenuringDistribution 這個參數用於顯示每次Minor GC時Survivor區中各個年齡段的對象的大小。 【4】-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold 用於設置晉升到老年代的對象年齡的最小值和最大值,每一個對象在堅持過一次Minor GC以後,年齡就加1。
相關文章
相關標籤/搜索