JVM系列(八) JVM 垃圾收集算法

前面我们了解了很多JVM配置垃圾回收的方式,但是具体垃圾是如何被回收的,或者说垃圾回收算法有哪些?今天我们文章主要讲解一下垃圾回收算法

1.分代收集理论

我们都知道 很早的JVM会把堆分为几个区域,新生代,老年代,永久代等区域,为什么要这么划分?就是为了区分对象的区域,从而根据区域去进行划分,为了分代收集

分代收集指

  • 垃圾收集器应该将Java堆划分 出不同的区域
  • 需要回收的对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储。
  • 一般至少将把Java堆划分为新生代 (Young Generation)和老年代(Old Generation)两个区域
  • 在新生代中,每次垃圾收集 时都发现有大批对象死去,而每次回收后存活的少量对象
  • 少量存活的对象将会逐步晋升到老年代中存放。

在此,对于分代收集理论存在两个分代假说:

  • 绝大部分对象是熬不过第一次垃圾回收的
  • 熬过多次垃圾回收的对象是难以被标记为垃圾的。

将堆划分为不同的区域后,垃圾回收器可以只回收其中一部分区域,针对每一部分区域也可以采用不同的算法来进行回收垃圾。

一般来说堆中至少会被划分为“新生代”和“老年代”两个区域。新生代存储第一种假说类型的对象,老年代存放第二种假说类型的对象。

注意:这种设计看起来是完美的,但是如果老年代中的对象引用了新生代中的对象这个时候年轻代发生垃圾回收时,除了需要遍历GC Roots外,还需要遍历整个老年代才会确保年轻代中的对象真正没有对象引用。显然这种遍历整个老年代效率肯定会很低

因此我们先介绍第一种垃圾收集算法

2.标记-清除算法

最早出现的垃圾回收算法,之后出现的算法都是根据该算法的缺点来进行演进的。

标记-清除算法 看名字就可以知道,分为两个阶段

  • 标记阶段
    • 标记需要回收的对象完成后进行统一回收所有被标记的对象
    • 也可以标记存活的对象统一回收没有被标记的对象。
  • 清除阶段
    • 进行统一回收掉标记的对象
      就像图片中呈现的,标记出来 存活的对象,可回收的对象(红色),然后清除阶段 对可回收的对象进行回收清除
      image.png
2.1 标记清除算法的缺点
  • 标记清除效率 不稳定
    • 标记出来需要回收的对象,如果此时有大量的对象要回收,那么就需要大量的标记和清除动作,所以就会导致导致标记和清除两个过程的执行效率都随对象数量增长而降低
    • 当对象超出限制的时候,那么就会因为没有及时的清除而导致对象无法回收,效率不稳定
    • 清除可回收对象后,区域之间是不连续的,会产生大量不连续的内存碎片,空间碎片太多可能会导致需要分配较大对象时无法找到足够的连续内存
    • 没有大空间就不得不提前触发再一次垃圾收集动作
3.标记-复制算法

标记复制算法,根据名字可以知道,他的垃圾回收过程中出 现了复制的操作?具体是复制什么操作呢?复制到哪里呢?下面我们讲解下

标记-复制算法

  • 采用的是"复制"算法来实现的,即每次只使用其中的一部分内存
  • 当这部分内存用完后将存活着的对象复制到另外一块内存上,接着清空刚才使用的那部分内存
  • 当另一部分内存满了的时候再用上一次清空后的那块内存,以此往复,来回切换
  • 对比标记清除算法,,因为他会把内存全部复制迁移到另一半区,记复制算法解决了内存碎片化的问题,不存在不连续的碎片内存

image.png

3.1 标记复制算法的缺点

标记复制算法把新生代分为了 Eden区/Survival区

  • Survival区分为 From区和To区 1:1
  • Eden/from/to 大小为8:1:1
  • 可用的90%,会存在10%的空闲区域资源浪费
  • 当存活的对象超出10%时的时候,Survival区放不下,就需要用老年代来存储,放到老年代中

所以标记-复制算法存在以下缺点

  • 内存中的对象存活率较高时,需要from/to来回复制大量存活对象,使得回收效率变低。
  • 如果不想造成严重的内存浪费,就需要有额外的空间进行分配
  • 内存利用率最大只能达到90%
4.标记-整理算法

标记-清除算法适用于新生代,对象用完直接清除掉,但是因为老年代中存活率较高,存放不下时需要额外的内存空间担保,清除不能解决问题,因为大部分对象都不需要清除,就是因为这个原因,所以才出现了标记整理算法

  • 过程和标记-清除算法一致,标记垃圾过程一样的,标记的都是存活对象
  • 但是也是有区别的,对于标记完成的对象,不是统一的进行清理
  • 而是将所有的存活对象全部向内存空间一端移动,然后直接清理掉边界以外的内存。

这样有什么好处? 内存区域都在一端,同样不存在内存地址碎片,而且整理后,内存地址连续,更方便的进行分配

image.png

4.1 标记-整理算法缺点
  • 标记整理针对老年代,老年代大部分都是存活对象
  • 对于大部分都为存活对象,将这些对象都进行移动并且更新引用这些对象操作比较耗时
  • 更新引用需要暂停用户线程来保证用户线程访问对象不会出错,简称STW,“Stop the Word”
  • 其实不止整理算法里面移动对象更新引用需要STW,清除算法和复制算法中的标记清除都需要STW,只不过时间短

上面我们讲了几种对象的标记,清除,整理,回收的机制,现在做如下总结

  • 标记-整理算法意味着GC的时候要移动对象更新对象的引用,产生STW
  • 标记-清除算法意味着内存碎片化,内存地址不连续,没法分配大对象
  • 标记-复制算法意味着内存可用度不高,始终存在from/to区域用于复制
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值