為什么堆要分新生代和老年代呢?
假設一下,如果不分新老代,內存就一整塊,垃圾收集器每次都要把那些長期存在的對象,和生命周期很短的對象放在一起回收,一般長生命周期的對象可能跟應用生命周期一致,你基本回收不掉的,比如Spring 框架里面的Bean管理相關的對象(ApplicationContext),整個應用運行期間都存在,這種一般經過幾次回收最后都放在老年代,但是如果不區分新老代,每次都一起回收,性能消耗很大。
區分新老代之后,老年代放長期存活的對象,新生代就放生命周期短的對象,老年代對象很穩定,新生代回收不影響老年代,回收效率能大大提高。
新生代為什么不用垃圾清除或者垃圾整理算法
若是在新生代使用垃圾清除或者垃圾整理算法,顯然不需要對新生代進行分區。
若是采用標記清除算法:會在新生代產生內存碎片,但是新生代是Java 新對象的出生地,內存碎片化顯然是我們不想看到的;
若是采用標記整理算法:雖然標記整理可以解決內存碎片化問題,但是考慮到新生代98%的對象都是“朝生夕死”的,對象被回收掉后會產生很多內存碎片,我們移動存活對象的時候需要耗費大量的時間,遠不如直接把這2%對象放到另一個地方采用復制算法更加高效。
為什么新生代還要分Eden、From、To區域呢?
前面的分析我們已經得出結論:新生代采用復制算法更加高效。
如果沒有Survivor區(From + To),Minor GC(新生代回收)過程中,存活的對象直接被送到老年代,這樣的話老年代很快被填滿,觸發Major GC(因為Major GC一般伴隨着Minor GC,也可以看做觸發了Full GC),Full GC頻繁會影響程序的執行和響應速度。
為什么要設置兩個Survivor區呢?From 和 To
前面的分析我們已經得出結論:新生代采用復制算法更加高效,且需要對新生代進行分區。
主要還是效率問題,假設將新生代分為Eden和Survivor兩個區域,顯然對Eden區采用復制算法,對Survivor區采用標記整理算法,這樣又回到在新生代使用復制算法效率比標記整理效率高的分析。所以需要通過將Survivor區分為From 和 To區解決。