GC 算法与种类

13 篇文章 0 订阅


1. 引用计数法

  • 原理
    引用计数器的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用。
  • 图例

在这里插入图片描述

  • 问题
  1. 引用和去引用伴随加法和减法,影响性能
  2. 很难处理循环引用
    在这里插入图片描述

2. 标记清除

  • 原理
    标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。
  • 图例
    在这里插入图片描述

3. 标记压缩

  • 原理

标记-压缩算法适合用于存活对象较多的场合,如老年代。它在标记-清除算法的基础上做了一些优化。和标记-清除算法一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间

  • 图例
    在这里插入图片描述

4. 复制算法

  • 原理
  1. 与标记-清除算法相比,复制算法是一种相对高效的回收方法
  2. 不适用于存活对象较多的场合 如老年代
  3. 将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收
  • 图例
  • 在这里插入图片描述
  • 问题
  1. 空间浪费
  2. 整合标记清理思想
    在这里插入图片描述

5. GC算法总结

  • 引用计数
    没有被Java采用
  • 标记-清除
  1. 效率问题
    标记和清除过程的效率都不高
  2. 空间问题
    标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作
  • 标记-压缩
  1. 优点:
    堆的利用效率高
  2. 缺点:
    需要多次搜索整个堆,所以,吞吐量较低(耗时较长)需要多次搜索整个堆,所以,吞吐量较低(耗时较长)
  • 复制算法

    实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半

  • 标记-清除标记-压缩对比

    标记–压缩算法的标记阶段和标记–清除算法的标记阶段是一致的,就不再重复。使用标记–压缩算法时,标记完可达对象之后,我们不再遍历所有对象清扫垃圾了,我们只需要将所有存活对象向“左”靠齐,让不连续的空间变成连续的,这样就没有内存碎片了。不仅如此,因为不再连续的空间变成连续的,内存分配也更快速了。

    对于标记–清除算法来说,因为内存中有碎片,空闲内存不再连续,为了分配内存,系统内可能要维护着一个空闲内存空间的链表。当需要分配内存时,会遍历这个链表,找到一个够大的内存块,然后将其分成两份,一份用作当前的分配,另一份放回链表(这样有造成更多的内存碎片,也有一些策略并不是按顺序查找,找到够大的就好,有可能是找到一个更好的空闲内存块为止)。而对于标记–压缩算法,内存空间是连续的,我们只需要一个指针标记出下一次分配工作要从哪里开始就可以了,分配后将指针递增所分配对象的大小,这个工作是非常快速的,而且不用维护那个空间内存链表了。

    这样一看好像标记–压缩算法绝对的优于标记–清除算法,那标记–清除还有啥存在的必要了呢?不过要记住的一点是标记–压缩算法为了达到压缩的目的,是需要移动对象的,这会有性能消耗的,这样所有对象的引用都必须更新。看来有利必有弊。

所有的算法,需要能够识别一个垃圾对象,因此需要给出一个可触及性的定义

6. 可触及性

  • 可触及的
  1. 从根节点可以触及到这个对象
  • 可复活的
  1. 一旦所有引用被释放,就是可复活状态
  2. 因为在finalize()中可能复活该对象
  • 不可触及的
  1. finalize()后,可能会进入不可触及状态
  2. 不可触及的对象不可能复活
  3. 可以回收
  • 经验
  1. 避免使用finalize(),操作不慎可能导致错误
  2. 优先级低,何时被调用, 不确定,何时发生GC不确定,可以使用try-catch-finally来替代它
  1. 栈中引用的对象
  2. 方法区中静态成员或者常量引用的对象(全局对象)
  3. JNI方法栈中引用对象

7. Stop-The-World

  • 分析
  1. Java中一种全局暂停的现象
  2. 全局停顿,所有Java代码停止,native代码可以执行,但不能和JVM交互
  3. 多半由于GC引起
    • Dump线程
    • 死锁检查
    • 堆Dump
  • GC时为什么会有全局停顿?
  1. 类比在聚会时打扫房间,聚会时很乱,又有新的垃圾产生,房间永远打扫不干净,只有让大家停止活动了,才能将房间打扫干净。
  • 危害
  1. 长时间服务停止,没有响应
  2. 遇到HA系统,可能引起主备切换,严重危害生产环境
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

superbeyone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值