JVM几种垃圾回收算法

1、标记-清除算法

标记-清除算法分为“标记”和“清除”两个阶段,执行过程如下图所示:
1、标记:首先标记出所有需要回收的对象
2、清除:在标记完成后统一回收所有被标记的对象

JVM几种垃圾回收算法_第1张图片
标记-清除算法主要有两个不足:
1、效率问题,标记和清除的两个过程效率都不高
2、标记-清除会产生大量不连续的内存碎片,这会导致在后面需要分配连续的大对象时,无法找到足够大的连续内存而导致不得不提前触发另一次垃圾收集动作。

2、复制算法

复制算法的大致思路如下,其执行过程如下图所示:
1、首先将可用内存分为大小相等的两块,每次只使用其中的一块。
2、当这一块的内存用完了,就将还存活的对象连续复制到另一块上面,然后把使用过的内存空间一次清理掉。
复制算法的代价就是将内存缩小为原来的一半。
JVM几种垃圾回收算法_第2张图片
现在的商业虚拟机都是采用复制算法来回收新生代。
1、新生代的内存分为一块较大的Eden空间和两块较小的Survivor空间。
2、每次使用Eden和一块Survivor,当进行回收时,将Eden和Survivor中还存活的对象一次性复制到另一个Survivor空间上。然后,清理掉Eden和刚刚使用过的Survivor空间。
3、HotSpot虚拟机默认Eden和Survivor的大小比例为8 : 1,这样每次新生代可用内存为整个新生代的90% (10% + 80%),只有10%的内存会被浪费。

3、标记-整理算法

标记-整理算法分为“标记”和“整理”两个阶段,执行过程如下图所示:
1、标记:首先标记出所有需要回收的对象
2、整理:让所有的存活的对象都向一端移动,然后直接清除掉边界以外的内存。JVM几种垃圾回收算法_第3张图片
标记-整理算法 采用和 标记-清除算法 一样的方式进行对象的标记,但后续不直接对可回收对象进行清理,而是将所有的存活对象往一端空闲空间移动,然后清理掉端边界以外的内存空间。

  • 优点:解决了标记-清理算法存在的内存碎片问题。
  • 缺点:仍需要进行局部对象移动,一定程度上降低了效率。

4、分代收集算法

当前商业虚拟机都采用分代收集的垃圾收集算法。分代收集算法,顾名思义是根据对象的存活周期将内存划分为几块。一般包括年轻代、老年代 和 永久代,如图所示:

JVM几种垃圾回收算法_第4张图片

新生代(Young generation)

绝大多数最新被创建的对象会被分配到这里,由于大部分对象在创建后会很快变得不可达,所以很多对象被创建在新生代,然后消失。对象从这个区域消失的过程我们称之为 minor GC。
新生代 中存在一个Eden区和两个Survivor区。新对象会首先分配在Eden中(如果新对象过大,会直接分配在老年代中)。在GC中,Eden中的对象会被移动到Survivor中,直至对象满足一定的年纪(定义为熬过GC的次数),会被移动到老年代
可以设置新生代和老年代的相对大小。这种方式的优点是新生代大小会随着整个堆大小动态扩展。

参数 -XX:NewRatio 设置老年代与新生代的比例。例如 -XX:NewRatio=8 指定 老年代/新生代 为8/1. 老年代 占堆大小的 7/8 ,新生代 占堆大小的 1/8(默认即是 1/8)。

老年代(old generation)

对象没有变得不可达,并且从新生代中存活下来,会被拷贝到这里。其所占用的空间要比新生代多。也正由于其相对较大的空间,发生在老年代上的GC要比新生代要少得多。对象从老年代中消失的过程,可以称之为major GC(或者full GC)。

小结

JDK8堆内存一般是划分为年轻代老年代不同年代根据自身特性采用不同的垃圾收集算法

  • 对于新生代,每次GC时都有大量的对象死亡,只有少量对象存活。考虑到复制成本低,适合采用复制算法。因此有了From Survivor和To Survivor区域。
  • 对于老年代,因为对象存活率高,没有额外的内存空间对它进行担保。因而适合采用标记-清理算法和标记-整理算法进行回收。

你可能感兴趣的:(JVM虚拟机,java,面试,开发语言)