【深入了解Java虚拟机】三、垃圾回收算法(标记-清除算法、复制算法(新生代算法)、标记-整理算法(老年代回收算法)、分代收集算法、Minor GC、Major GC与Full GC的区别?

1. 垃圾回收算法

1.1 标记-清除法

"标记-清除"算法是最基础的收集算法。算法分为"标记"和"清除"两个阶段

  1. 标记出所有需要回收的对象(遍历堆标记)
  2. 标记完成后统一回收所有被标记的对象(遍历堆删除)

"标记-清除"算法的不足之处:

  1. 效率问题:标记 和 清除这两个过程效率都不高。
  2. 空间问题:标记和清除后会产生大量 不连续的 内存碎片,空间碎片太多 可能会导致 以后在程序运行中 需要分配较大对象时,无法找到足够连续内存而不得不触发一次垃圾回收,触发一次之后要是内存还不够,就会连续触发,导致OOM

【深入了解Java虚拟机】三、垃圾回收算法(标记-清除算法、复制算法(新生代算法)、标记-整理算法(老年代回收算法)、分代收集算法、Minor GC、Major GC与Full GC的区别?

1.2 复制算法(新生代算法)

  "复制"算法是为了解决"标记-清理"的效率问题。它将可用内存 按容量划分为大小相等的两块,每次只使用其中的一块,当这块内存需要垃圾回收时,会将此区域还活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。这样做的好处是每次都是对整个半区进行内存回收,内存分配时也就不需要考虑内存碎片等复杂情况,只需要按序分配即可。此方法实现简单,运行高效。
【深入了解Java虚拟机】三、垃圾回收算法(标记-清除算法、复制算法(新生代算法)、标记-整理算法(老年代回收算法)、分代收集算法、Minor GC、Major GC与Full GC的区别?
  新生代中98%的对象都是 ‘‘朝生夕死’’ 的,所以并不需要按照1:1的比例来划分空间,而是将内存(新生代内存)分为一块**比较大的Eden(伊甸园)两块较小的Survivor(幸存者)**空间,每次使用Eden和其中一块Survivor(两个Survivor区域一个称为From区,另一个称为To区)。当回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间

HotSpot默认Eden:Survivor From:Survivor To=8:1:1,所以每次新生代可用内存空间为整个新生代容量的90%,而剩下的10%用来存放回收后存活的对象。

当Survivor空间不够用时,需要依赖其它内存(老年代进行分配担保)

HotSpot实现复制算法的流程:

  1. 当Eden区满的时候,会触发第一次Minor gc,把还活着的对象拷贝到Survivor From区;当Eden区再次触发Minor gc的时候,会扫描Eden和From区域,对两个区域进行垃圾回收,经过这次回收后还存活的对象,直接赋值到To区域,并将Eden和From区域清空。
  2. 当后续Eden又发生Minor gc的时候,会对Eden和To区域进行垃圾回收,存活的对象复制到From区域,并将Eden和To区域清空。
  3. 部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认是15),最终还是存活,就存入老年代。

1.3 标记-整理算法(老年代回收算法)

  复制算法 在对象存活率较高时 会进行比较多的复制操作,效率会变低。因此在老年代一般不能使用复制算法。针对老年代的特点,提出了一种称之为"标记-整理"算法。标记过程仍与"标记-清除"中标记的过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉端边界(除存活对象)以外的内存。
【深入了解Java虚拟机】三、垃圾回收算法(标记-清除算法、复制算法(新生代算法)、标记-整理算法(老年代回收算法)、分代收集算法、Minor GC、Major GC与Full GC的区别?

1.4 分代收集算法

当前JVM垃圾收集都采用的是"分代收集"算法,这个算法并没有新思想,只是根据对象存活周期的不同将内存划分为几块。
一般是把Java堆分为新生代和老年代。在新生代中,每次垃圾回收都有大批的对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象的存活率高,没有额外空间对他进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。

1.5 Minor GC、Major GC、Full GC的区别?

堆内存划分为Eden、Survivor、和Tenured/Old空间

  • Minor GC 又称为新生代GC 指的是发生在新生代的垃圾回收操作(包括Eden区和Survivor区)。当JVM无法为一个新的对象分配空间时候,会触发Minor GC。因为新生代中大多数对象的生命周期都很短,因此Minor GC(采用复制算法)非常频繁,虽然它会触发stop-the-world,但是回收速度也比较快。

  • Major GC清理老年代,出现Major GC通常会出现至少一次Minor GC即大多数Major GC是由Minor GC触发的

  • Full GC是针对整个堆空间包括新生代、老年代、元空间GC,Full GC不等于Major GC,也不等于Minor GC+Major GC。