GC回收算法

GC就是Garbage Collection,垃圾收集,GC的对象是Java堆和方法区(永久),所谓的垃圾是指在系统运行期间产生的一些无用的对象,而这些对象占有一定的内存空间,如果长期不释放就很有可能导致OOM(内存溢出)。

标记-清除算法

标记清除算法是最基础的垃圾收集算法,分为标记和清除两个阶段。首先会标记出所有需要回收的对象,在标记完成后统一对需要回收的对象进行回收。如下图:

在这里插入图片描述

在上图中,黑色代表需要被回收的,灰色代表存活的对象,白色表示未使用的对象。黑色的部分是要标记的部分,回收完成后变成白色部分。这样一来,我们可以总结出标记清除算法的两个缺点:

1.标记和清除这两个过程的效率都非常低
2.产生不连续的内存碎片,内存碎片过多会导致以后在给一个较大的对象分配内存时无法找到一块连续的内存空间而不得不提前触发另一次垃圾收集。

复制算法(新生代回收算法)

复制算法是为了解决标记清除算法的效率低的问题,它将可用内存分为大小相等的两块区域,每次只使用一块区域,当使用的这块内存需要垃圾回收的时候,会将这块区域还存活的对象复制到另一块,再将这一块使用过的对象一次性一块清理。这样就不需要考虑内存碎片等复杂的情况,因为每次都是对整个半区进行回收的。

在这里插入图片描述
如上图所示,蓝色代表内存,分为左右两个大小相等的内存。
现在的商用虚拟机包括hotspot都使用这种算法回收新生代

新生代中98%的对象都是"朝生夕死"的,所以并不需要按照1 : 1的比例来划分内存空间,而是将内存(新生代内存)分为一块较大的Eden(伊甸园)空间和两块较小的Survivor(幸存者)空间,每次使用Eden和其中一Survivor(一个Survivor区域一个称为From区,另一个称为To区域)。当回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。

HotSpot默认Eden与Survivor的大小比例是8 : 1,也就是说Eden:Survivor From : Survivor To = 8:1:1。所以每次
新生代可用内存空间为整个新生代容量的90%,而剩下的10%用来存放回收后存活的对象。
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),最终如果还是存活,就存入到老年代

在这里插入图片描述

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

复制算法一般当对象存活比较高的时候会进行较多的复制,这样效率就会变得很低,所以在老年代一般不使用这种算法。而是用标记整理算法。标记整理算法和标记清除算法前面的步骤一样,但后续不是直接对可回收的对象进行清理,而是让所有存活的对象都向一端移动,然后将端以外边界的内存都清理掉。如图:

在这里插入图片描述

分代收集算法

当前的JVM使用的都是分代收集算法,根据对象的存活周期的不同划分为几个块,一般是把Java堆分为新生代和老年代,新生代每次回收都有大批的对象死去,只有少量的对象存活,因此使用复制回收算法。老年代存活时间比较久,但是没有额外的空间对它分配担保,所以就必须采用标记清除或者标记整理算法。

面试题

请问了解Minor GC和Full GC么,这两种GC有什么不一样吗?

  1. Minor GC又称为新生代GC : 指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特
    性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。
  2. Full GC 又称为 老年代GC或者Major GC : 指发生在老年代的垃圾收集。出现了Major GC,经常会伴随
    至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器中就有直接进行Full GC的策略选择过程)。
    Major GC的速度一般会比Minor GC慢10倍以上。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章