深入理解新生代为什么要分两个Survivor区?

为什么堆要分新生代和老年代呢?

假设一下,如果不分新老代,内存就一整块,垃圾收集器每次都要把那些长期存在的对象,和生命周期很短的对象放在一起回收,一般长生命周期的对象可能跟应用生命周期一致,你基本回收不掉的,比如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区解决。

posted @ 2021-08-11 09:55  Coder豪  阅读(764)  评论(0编辑  收藏  举报