淺談新生代爲什麼要分三塊區域並且比例爲什麼是8:1:1

  如題最近網上看到了一個某大廠的面試題,新生代爲什麼分區網上答案比比皆是,爲什麼是8:1:1我是沒搜到什麼有價值的答案,今天結合這個題目談談自己的粗淺想法,如有不對還望指正;另外需要說明的是,接下來聊的都是基於G1之前的垃圾收集器;

  首先,我們假設新生代如果不分代會發生什麼,如果不分代的話那麼堆內存就是一塊新生代,一塊老年代,當發生mionrGc時,收集器不管採用的是古老的Serial還是Parallel Scavenge,都會使用標記-複製算法將新生代中存活的對象直接複製到老年代;

這時候會產生如下問題:1.原先本來可作爲擔保空間的老年代直接用來容納了每次gc存活的對象,導致了標記-複製算法沒有了擔保空間,大大新增了fullGC發生的概率和次數

           2.無論對象年齡與否,只要熬過一次垃圾回收即可進入老年代,使進入老年代的成本降低,加大了老年代的負擔,同樣會增加fullGc的次數

  所以由上可得,新生代必須分代,此時我們假設將新生代分成一個e區一個s區,如圖:

  

 

 

  我們來看下在此分代模式下進行mionrGC會發生什麼,第一次gc時存活對象由e區進入s區然後清空e區,此時老年代也可以啓擔保作用,一切看起來都很正常;但是如果再發生第二次gc會怎樣呢,此時e區有存活對象而容納第一次gc時存活對象的s區也

肯定會有存活對象,此時需要將e,s區的存活對象複製到老年代,此時,問題也就顯而易見了,與不分代的時候情形一樣了,對象只能進入老年代;另外還有個比較嚴重的問題是,新生代分兩區的話加上採用的是複製算法,那麼不可避免的會產生垃圾碎片;

所以我們要將新生代再開闢一塊區域來當作一個攔截器,不讓不達年齡的對象直接接入老年代;結構如圖:

 

 

 

此時新生代分成了e區,s0區和s1區;這時候再發生mionrGc就不會有上面出現的問題了:第一次GC時存活對象由e進入s0,然後清空e區;第二次gc時將e區和s0區的存活對象複製到s1區,清空e區和s0;第三次將e區和s1的對象複製到s0,清空e和s1。。。。。。

無論多少次mionrGc,如此反覆,直到對象年齡達標或者s區(s0或s1)容不下存活對象時再晉升到老年代,這樣也就降低了老年代的壓力,減少了fullGc的次數;

以上的廢話假設了各種不分塊或分兩塊的利弊,其實在深入理解java虛擬機裏接一小段話,大家可以參考下,就是P。頁對標記-複製算法的講解;

  所以個人認爲的新生代分分區或分三區的原因如下:1.降低老年代的內存分配壓力,通過設置兩個s區來對年輕對象進行攔截,降低fullGc的次數

                         2.分三代能使老年代作爲擔保來應付s區容不下存活對象的情況

  接下來我們來討論下爲什麼e:s0:s1默認是8:1:1?

  深入理解虛擬機一書裏有描述,IBM的一項研究,表明新生代中有98%的對象是朝生夕滅的,換言之,每次mionrGC後存活的對象應該小於等於2%,所以看起來採用複製算法的新生代似乎可以不用將內存分成大小相等的兩塊了,但考慮到實驗偏差以及實際情況的多樣性,jvm

默認預留了10%的內存用於存放存活對象,此時結合上文描述的,新生代最優應該分成三塊,所以得再預留一塊10%的內存給s區,那麼自然剩下的80%就是e區的大小了;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章