Java垃圾回收之回收算法
光有垃圾标记算法还不行,JVM还需要有垃圾回收算法来将这些标记为垃圾的对象给释放回收掉。主要的回收算法有以下几种:
1.标记 - 清除算法(Mark and Sweep):
- 标记:从根集合进行扫描,对存活的对象进行标记
- 清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存
缺点
- 效率问题:标记 和 清除这两个过程效率都不高。
- 空间问题:标记和清除后会产生大量 不连续的 内存碎片,空间碎片太多 可能会导致 以后在程序运行中 需要分配较大对象时,无法找到足够连续内存而不得不触发一次垃圾回收,触发一次之后要是内存还不够,就会连续触发,导致OOM
2.复制算法(Copying):
- 将可用的内存容量按一定比例划分为两块或多块,并将其中一块或两块作为对象面,剩余的则作为空闲面
- 对象在对象面上创建,当对象面的内存空间用完时,会将存活的对象从对象面复制到空闲面中,接着清除该对象面中所有的对象
优点:解决内存碎片化问题,顺序分配内存,简单高效。该算法适用于对象存活率低的场景,所以普遍应用在新生代中,因为新生代里的对象存活率通常情况下只有10%左右
3.标记 - 整理算法(Compacting):
- 标记:从根集合进行扫描,对存活的对象进行标记
- 整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收
优点:避免了标记 - 清除算法所带来的内存不连续性问题,以及不需要像复制算法那样需要设置两块内存互换。该算法适用于对象存活率较高的场景,所以普遍应用在老年代中,因为老年代里对象存活率较高
4.分代收集算法(Generational Collector):
- 实际是多种垃圾回收算法的组合拳,该算法对堆内存进行进一步的划分,按照对象生命周期的不同划分区域以采用不同的垃圾回收算法。目的是提高JVM的回收效率,也是目前JVM使用的回收算法
一般是把Java堆分为新生代和老年代。在新生代中,每次垃圾回收都有大批的对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象的存活率高,没有额外空间对他进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。
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。