JVM垃圾回收之垃圾回收算法

1.背景

上一篇博客介绍了在垃圾回收时哪些对象可以被回收,这一篇主要来介绍怎么回收,即垃圾回收的算法和思想。在JVM中主要有三种回收算法:标记清除算法、标记整理算法和复制算法。如果说这三种算法属于战术层面上的算法,那么分代回收算法就是战略层面的算法。换句话说,上述三种垃圾回收算法都要在分代回收算法的前提下进行。可能听起来还是有点懵,看完下面的介绍应该就会比较清楚了。

2.垃圾回收算法

2.1 标记清除算法

标记清除算法就如同其名字一样,主要分为标记和清除两个阶段。标记阶段,采用可达性分析算法标记出所有可以被回收的对象。清除阶段,将被回收的对象清除。它的过程可以用如下的图片近似表示,其中白色的方块为空闲区域,黑色方块为已经占用的堆内存区域,灰色方块为可回收的区域。

  • 初始状态

  • 标记完成后

  • 清除完成后

从上面的过程可以看出,标记清除算法思路比较简单,实现起来也稍微容易点。但是这种算法有一个最大的缺点就是会产生内存碎片,导致内存不连续。这样的话,对于一个大对象,有可能会出现剩余的内存大于这个对象,但是并没有足够的连续内存来存放这个对象,进而导致OOM。

2.2 标记整理算法

标记整理算法,相比于标记清除算法,多了整理阶段,一共分为标记、整理和清除三个阶段。其中,整理阶段会将所有存活的对象移动到堆内存的一端,然后清除阶段将剩下的垃圾清除掉。它的过程可以用下图表示。

  • 初始阶段

  • 标记完成后

  • 整理完成后

  • 清除完成后

相对于标记清除,标记整理算法不会产生内存碎片。但它增加了回收的复杂度,比如在内存整理的过程中很多对象的物理地址都会发生变化,为了保证程序的正常运行,那么原先指向这些对象的引用都需要改变指向,而且也会增加垃圾回收的时间。

2.3 复制算法

所谓复制算法,就是将堆内存分为A和B两半,使用的时候只使用A部分,当需要进行垃圾回收时,将A部分存活的对象复制到B部分,然后将A部分全部清空。下一次使用的时候使用B部分,依次类推。它的过程可以用下图表示。

  • 初始阶段

  • 标记结束后

  • 复制结束后

  • 清理结束后

从实现过程可以看出,复制算法不会产生内存碎片,整个过程相比于标记整理也更加简单,易实现。但是,复制算法有一个比较大的问题就是有一半的内存必须是空闲的。因此,上述三种垃圾回收算法各有自己的特点,必须结合具体的使用场景加以选择。

3.分代垃圾回收

上面已经介绍了三种垃圾回收算法,那么分代垃圾回收又是什么呢?分代垃圾回收是一种思想,是一种战略层面的回收算法。之所以会有这个东西,主要原因是Java中的对象大部分都是朝生夕死的,而另外一部分对象存活的时间比较长。对于垃圾回收来说,没有必要每次都去尝试回收那些存活时间比较久的对象,因为大概率回收不掉。为了实现这个想法,分代垃圾回收应运而生。所谓分代垃圾回收,其主要思想是将堆内存分为两个部分:年轻代和老年代。年轻代存放那些生命周期比较短的对象,老年代存放生命周期长的对象。在内存不足时,先去回收年轻代的内存,这样的回收效率更高,如果年轻代回收过后,内存依然不够用,再去回收老年代的内存。另外,由于年轻代和老年代的特点,可以采取不同的垃圾回收算法。通常情况下,由于年轻代每次回收后存活的对象比较少,采用复制算法更合适;对于老年代,对象存活率比较高,如果也采用复制算法的话,就需要开辟一块相当大的空闲内存供复制使用,因此老年代通常采用标记清除或标记整理算法。

4.总结

  • 常用的有标记清除、标记整理和复制三种垃圾回收算法
  • 分代垃圾回收将堆内存划分为年轻代和老年代
  • 年轻代通常使用复制算法进行垃圾回收;而老年代采用标记清除或标记整理算法
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值