因为年轻代和老年代的特点不同,需要用不同的垃圾回收算法;
老年代的对象,他的特点是需要长期存活,所以需要另外一种垃圾回收算法;
所以需要分为两个区域去存放不同的对象;
1、绝大多数对象都是朝生夕死的;
如果一个区域里面的对象大多都是朝生夕死的,你们就把他们集中在一起,每次回收的时候只关注如何保留少量存活对象,而不是去标记哪些大量将要被回收的对象,就能以较低的待机回收大量的空间;
2、熬过了很多次垃圾收集的对象就越难回收;
如果是需要长期存活的对象,就把他们集中放在一起,虚拟机就可以使用较低的频率来回收这个区域,这样就兼顾了垃圾收集的时间开销和内存的空间有效利用;
3、JVM划分出新生代和老年代之后,垃圾收集器可以每次只回收其中某一个部分或者某些部分的区域,同时有了 Minor GC Major GC Full GC这样的回收类型划分;
Minor GC:新生代收集
Major GC:老年代收集、
Full GC:整堆收集:收集新生代、老年代以及元空间(方法区)的垃圾收集;
Mixed GC:混合收集,收集整个新生代及部分老年代的垃圾收集,目前只有G1收集器会有这种行为;
4、根据不同区域对象的存亡特征采用不同的垃圾收集算法:
标记-复制算法
标记-清除算法
标记-整理算法
1、如果没有Survivor区
这个时候当Eden区域满了之后,每出发一次Minor GC就会把Eden区的对象复制到老年代,这样当老年代满了之后就会出发Major GC\Full GC,频繁出发Full GC会影响性能;
2、如果只有一个Survivor区
创建的对象在Eden中,一旦Eden满了,出发一次Minor GC,Eden中存活的对象就会被移动到Survivor区,下一次Eden满了之后,此时进行Minor GC,Eden和Survivor区域就会将存活的对象存放到老年区,但是这样的垃圾清除会导致Survivor区域会出现内存碎片的问题,当下一次Eden中有一个大对象的时候,可能导致没有一个连续的空间存放,就会触发Minor GC,影响性能;救国不想出现内存碎片还可以进行标记-整理算法,但是标记整理算法又会耗费开销,影响性能;
1、 标记-清除算法
1、标记
标记处所需要回收的对象在,在标记完成之后,统一回收掉所有被标记的对象,也可以反过来,标记处所有存活的对象,在标记完成之后,统一回收所有未被标记的对象,标记过程就是判断对象是否属于垃圾的过程,基于可达性分析算法判断对象是否可以回收;
2、清除
对被标记为垃圾的对象进行回收;
优点:
基于可达性分析算法,算法实现简单,后续收集算法都是基于这种思想实现的;
缺点:
1、执行效率不稳定,如果java堆中包含大量对象,而且其中大部分是需要被回收的,这是就必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低;
2、内存空间的碎片化问题,标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后再程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发一次垃圾收集;
2、复制算法 (新生代)
将内存按容量分为大小相等的两块,每次只是用其中一块,当这一块内存用完了,就将还存活的对象复制到另外一块内存上,然后把已使用过的内存空间一次清理掉;
优点:实现简单,效率高,解决了标记-清除算法导致的内存碎片问题;
缺点:
1、代价太大,将可分配内存缩小了一半,空间浪费太多;
2、对象存活率较高时,就要进行较多的复制操作,效率将会降低;
一般虚拟机都会采用该算法来回收新生代,但是JVM对复制算法进行改进,JVM并没有按照1:1的比例来划分新生代的内存空间,因为通过大量的统计和研究表明,90%的对象是需要被回收的;
就会把需要回收的对象复制到另外一块Survivor上面;
这样就只有10%的空间被浪费;这就是优化的地方