GC的回收算法



基本概念

JVM中GC(Garbage Collector)的回收最常见的四种基本算法:Mark-Sweep(标记-清除),Copying(复制),Mark-Compact(标记-整理),Generational Collection(分代收集)(其实还有火车算法,但因为很少使用在这里就不进行讨论)。这里所列出的算法是有先后顺序的,每一个算法是前面算法的优化。

其实在这一节不仅仅是要掌握GC常用的算法,还要理解是根据具体的储存结构特点选择使用适当的算法的思想。例如:在Java堆一部分区域会根据“新生代“和”老年代”一部分会采用复制算法,另一部分采用标记-清除算法。


下面是GC中常见的名词性解释:

  • collector:回收器(用于回收不在需要的内存)

  • mutator:更改器(对内存进行 分配,读取,写入)

  • Roots:根对象(可以由此处逐一访问Java堆上的所有对象)

  • 可达对象:在根对象上进行遍历,可被访问的对象实例

    状态
    可用不可达易造成内存泄漏
    不可用不可达回收的内容
    可用可达正常

GC的原理:当一个对象实例的引用计数为0(引用计数法)或者是没能和Roots构成引用链的 即Roots根对象没能遍历到的对象(可达性分析法),则可能被GC进行回收。

本文是基于可达性分析法后的GC回收处理



根对象(Roots)

什么是根对象?

  • 虚拟机栈的局部变量表引用的对象
  • 方法区的类变量与常量引用的对象(JDK1.8后变成Java元数据区的类变量与常量引用的对象)
  • 本地方法栈中JNI引用的对象

在这里插入图片描述

若不能和Roots对象构成引用链,那么该内存区域将会被回收



标记

标记在GC中是一个很重要的概念,它是确认哪部分内存需要回收的唯一标识,所以在可达性分析法下的垃圾回收算法中都需要用到。

实际上,JVM在回收前对目标会做两次标记。

流程如下:

1.第一次标记:对没能和Roots构成引用链的对象进行标记,划入可回收集合

2.对标记成员进行筛选

​ 2.1 覆盖或者未调用过finalize()方法的成员,会进入需要执行finalize()方法的队列

​ 2.2 对未覆盖或者已经调用过finalize()方法的成员,已经是可回收状态了

3.第二次标记:对队列中的成员进行筛选

​ 3.1 执行完finalize()方法,便可以回收了

​ 3.2 若在执行finalize()方法过程中,与Roots对象又构成引用链,则该对象实例会被移出可回收集合。

下面开始讨论几种回收算法



Mark-Sweep算法(标记-清除 算法)

在这里插入图片描述

标记-清除算法是其他GC算法的基础,它提出了一种在可达性分析后进行回收的方式。

1.标记:在遍历Roots对象后,找到未能和Roots对象构成引用链的对象进行标记(两次标记)

2.清除:两次标记后,仍在可回收集合中的对象将被清除


优点:实现较简单,开销小

缺点:垃圾回收后,因为没有对空间进行整理,导致内存不连续变得碎片化。在这种情况下,如果需要分配一个较大的内存区域,可能会因没有空间而导致OOM



Copying算法(复制算法)

在这里插入图片描述

复制算法是为解决GC回收后内存碎片化而产生的。

调用后的过程如下:

1.将内存区域划分为两个区域,每次使用一个区域(区域大小非1:1)

2.在进行标记-清除算法后,将仍然存活的对象逐一复制到另一部分内存上

3.清除另一部分的内存


优点: 解决了标记-清除方式的内存不连续问题

缺点:
1.空间复杂度高

​ 2.随着对象存活率的升高,而时间复杂度变高


改良后的算法:针对新生代存活率低的特点,使用复制算法在这一区域上,并且使得复制算法的内存区域不用按照1:1分配。详见下面的分代收集算法



Mark-Compact(标记-整理算法)

在这里插入图片描述

标记-整理算法解决了复制算法随着对象存活率升高,时间复杂度变高的缺点。

调用后的过程如下:

1.执行标记-清除算法

2.将存活对象往一侧移动,并且清理边界外的内存区域


优点: 不会因为存活率变高,而效率降低

缺点: 时间复杂度较高



Generational Collection(分代收集算法)

  • 目前几乎所有商业虚拟机均采用了分代收集算法

  • 在(JDK1.8)JVM中,内存分成三个区域:新生代,老年代,元数据区(原是永久代)

  • 分代收集算法是基于复制算法和标记-整理算法的特点改良后的算法,专门针对新生代与老年代的特点进行设计。


新生代

作用: 存放新生的对象

特点: 创建对象频繁,但存活率低。老年代可作为空间不足时的备用内存使用。

内存结构简易图:

在这里插入图片描述

  • 分成三个区域: Eden、ServivorFrom、ServivorTo

    Eden区:每次创建对象分配空间的区域(但是如果对象所占空间太大,也可能会在老年区分配)

    ServivorFrom区:存放上次GC回收后,存活的对象

    ServivorTo区:存放当前GC回收后,存活的对象(进入该区域的对象年龄会+1)

GC回收算法: 复制算法

  • GC方式:MinorGC

  • 1.每次创建对象会在Eden中分配空间,若Eden空间不足,则调用MinorGC进行回收。

    2.将Eden区和ServivorFrom区进行标记,接着将存活对象复制到ServivorTo区上

    3.存活的对象满足年龄条件或者ServivorTo空间不足时,会将对象复制到老年代区域

    4.清除Eden区和ServivorFrom区

    5.交换ServivorFrom区域和ServivorTo区域,…执行1…


老年代

作用: 存放生命周期长的对象

特点: 存活率高,没有备用空间

内存结构简易图:

在这里插入图片描述

GC回收算法: 标记-整理

  • GC方式:MajorGC
  • 仅在调用MinorGC后,有对象从新生代进入老年代时,才会调用MajorGC
  • 该区域的GC回收,通常会使用标记-整理,而不是标记-清理(减少碎片化)
  • 该区域若空间不足以分给,会抛出OutOfMemory错误
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值