GC种类与算法

转自

GC 算法与种类
技术标签: GC 算法 JVM

文章目录

  1. 引用计数法
    原理
    图例
    问题
  2. 标记清除
    原理
    图例
  3. 标记压缩
    原理
    图例
  4. 复制算法
    原理
    图例
    问题
  5. GC算法总结
    引用计数
    标记-清除
    标记-压缩
    复制算法
    标记-清除标记-压缩对比
  6. 可触及性
    可触及的
    可复活的
    不可触及的
    经验
  7. Stop-The-World
    分析
    GC时为什么会有全局停顿?
    危害
  8. 引用计数法
    原理
    引用计数器的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用。
    在这里插入图片描述

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

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

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

图例
在这里插入图片描述

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

问题
空间浪费
整合标记清理思想
在这里插入图片描述

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

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

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

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

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

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

    栈中引用的对象
    方法区中静态成员或者常量引用的对象(全局对象)
    JNI方法栈中引用对象
  2. Stop-The-World
    分析
    Java中一种全局暂停的现象
    全局停顿,所有Java代码停止,native代码可以执行,但不能和JVM交互
    多半由于GC引起
    Dump线程
    死锁检查
    堆Dump
    GC时为什么会有全局停顿?
    类比在聚会时打扫房间,聚会时很乱,又有新的垃圾产生,房间永远打扫不干净,只有让大家停止活动了,才能将房间打扫干净。
    危害
    长时间服务停止,没有响应
    遇到HA系统,可能引起主备切换,严重危害生产环境
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值