JVM:GC的四种算法解析

本文章将着重用图描述引用计数器、复制算法、标记清除法、标记压缩法的实现原理以及过程

引用计数器

对于每一个对象,都会添加一个引用计数器,每当这个对象被引用时,其被引用的次数就会加1,如果对这个对象的引用失效时,那么就会减一。在任何时刻,只要当记录的次数为0时,那么这个对象就可以被回收(如下图所示)
在这里插入图片描述

在这里插入图片描述
优点:实现简单
缺点:程序计数器本身的创建就会消耗内存,而对每个对象引用次数记录也会影响的性能。因此该方式很少使用

复制算法

了解复制算法的实现过程,则需要了解Jvm堆的分区:
在这里插入图片描述

  • 伊甸园区:所有的对象都是在伊甸园区创建出来
  • 幸存区:在第一次垃圾回收后,没有被回收的对象存入幸存区
  • 老年区:在gc对幸存区进行垃圾回收后,依然没有被回收的对象进入老年区
  • 永久代/元空间:在JDK1.8之前,该区域被称为“永久代”,JDK1.8即之后,改为元空间。用来存放jdk自身携带的Class对象,Interface元数据,以及Java运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭虚拟机就会释放这个区域的内存。

在新生区中,存在有两个幸存区,这里我们命名为幸存区to和幸存区from。在Jvm实际的运行过程中,复制算法则是通过幸存区to和幸存区from不断的进行转换来进行垃圾回收,以下是执行过程:

  1. 进行第一次GC前两个幸存区均为空(为了区分,绿色和灰色均为被GC的垃圾对象,但是绿色表示为GC后未被删除的对象,灰色表示为GC后被删除的对象);在这里插入图片描述
  2. 第一次GC开始,所有被GC的对象进入幸存区,存储垃圾的幸存区为幸存区from,空幸存区为幸存区from
    在这里插入图片描述
  3. 幸存区from将幸存对象全部复制并传递至幸存区to中,其他对象则被回收,并且转为幸存区to,幸存区to接受原幸存区from传递过来的幸存对象,并且转为幸存区from。

在这里插入图片描述

总结:将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。

优点:实现简单且高效,不会产生内存碎片。
缺点:浪费了一半的内存空间用于转换,大大降低了内存的利用率

标记清除法

标记算法主要分为两个阶段:标记阶段和清除阶段

  1. 标记阶段:首先扫描所有对象,将依旧存活的对象进行标记

在这里插入图片描述

  1. 清除阶段:再次扫描所有对象将未标记的对象删除
    在这里插入图片描述
    优点:没有内存的浪费,无需额外的空间
    缺点:对象删除后会产生内存碎片,且扫描了两次,浪费了一定的性能

压缩清除算法

标记算法主要分为两个阶段:标记阶段、清除阶段、压缩阶段

  1. 标记阶段:首先扫描所有对象,将依旧存活的对象进行标记

在这里插入图片描述

  1. 清除阶段:扫描所有对象,将未标记的对象删除
    在这里插入图片描述

  2. 压缩阶段:再次扫描,向一端移动或者的对象

总结:不难得出,压缩清除算法其实是标记清楚法的一种优化,它的主要目的是为了解决代码块的生成。
优点:无需额外空间,且不产生代码块;
缺点:进行了多次扫描,一定程度上浪费了性能

总结

效率上比较:

  • 内存效率:复制算法>标记清楚算法>标记压缩算法(时间复杂度)
  • 内存整齐度:复制算法=标记压缩算法>标记清楚算法
  • 内存利用率:标记压缩算法=标记清除算法>复制算法

使用区间比较:
新生区:

  • 特点:存活率低
  • 使用复制算法

老年区:

  • 特点:区域大,存活率高
  • 标记清除+标记压缩混合实现
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值