前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM 系列(3) —— 垃圾回收算法

JVM 系列(3) —— 垃圾回收算法

作者头像
求和小熊猫
发布2020-12-22 16:06:59
3060
发布2020-12-22 16:06:59
举报

垃圾回收

如何判断对象已死

在 Java 对对象进行回收之前,需要判断哪些对象已死,哪些对象存活,常用的判断方法有两种: 引用计数法可达性分析法

引用计数法

引用计数法就是在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一,当引用失效时就减一。当计数器为 0 时,对象便不再被引用。

引用计数法虽然消耗了一些空间,但是原理简单,判定高效,在绝大多数情况下是一个不错的算法。但是引用计数法需要考虑到很多例外的情况,必须要配合大量的额外工作才能正确的工作,比如单纯引用计数法就很难解决对象之间相互循环引用的问题。

可达性分析法

通过一系列 “GC Roots” 的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,向下搜索的过程中所走过的路径称为 引用链(Reference Chain)。如果对象没有任何一条引用链路劲连接,即从任何一个 GC Roots 出发都不能到达该对象。

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

在 Java 中,GC Roots 包含:

  • 虚拟机栈中 (栈帧中局部变量表) 的引用对象
  • 方法区中静态类属性的引用对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI 引用的对象
  • Java 虚拟机内部引用的对象,比如基本数据类型对应的 class 对象以及一些常驻对象。
  • 被同步锁持有的对象
  • 反应 Java 虚拟机内部情况的 JMX Bean,与 JVMTI 中注册的回调和本地代码缓存

Java 中的引用

在 JDK 1.2 后,扩充了引用的概念,将引用依强度依次分为 强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)

强引用 强引用是指在程序代码中普遍存在的引用类型的赋值。一般只要强引用关系还在,垃圾收集器就永远不会被回收掉。

软引用 被软引用关联的对象,会在系统即将发生内存溢出异常前进行回收。

弱引用 被弱引用关联的对象只能生存到下一次垃圾收集为止。

虚引用 被虚引用关联的对象,既不会影响对象的生存时间,也无法通过虚引用获取对象实例,只是在该对象被回收时收到一个系统的通知。

垃圾回收过程

在进行垃圾回收是,首先会对对象进行可达性分析,若果发现对象没有与 GC Roots 相连接的链路,将会对对象进行第一次标记。然后看标记的对象是否覆盖了 finalize 方法或者 finalize 方法已经被虚拟机调用过了,如果没有覆盖或者已经被调用过了,则直接回收,如果没有则将对象放入到 F-Queue 中主备通过 Finalizer 线程去执行这些方法,在执行完之后,垃圾收集器会对对象进行二次标记,如果对象依旧北邮被 GC Roots 引用,则对象会被回收

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

finalize 方法只能被 jvm 调用一次,且对象被标记后只有通过 finalize 方法来逃脱,且只有一次逃离机会。

方法区的垃圾回收

在方法区 (又称元数据或永久代) 中,垃圾的回收对象为两种,废弃的常量不再使用的类型

废弃常量的判定: 判定一个常量是否是废弃常量只需要判断虚拟机中有没有其他地方引用这个常量。

不使用类型的判定:

  • 该类的所有实例被回收
  • 加载该类的加载器已经被回收
  • 该对象的 java.lang.class 对象没有在任何地方被引用

垃圾回收算法

分代收集理论

当前虚拟机的垃圾收集器,大多都遵循了“分代收集理论”,该理论依据实际情况和法则建立,也是建立在两个分代假说之上

分代假说

  1. 弱分代假说:绝大多数对象都是朝生夕灭的
  2. 强分代假说:越是熬过多次垃圾收集的对象,越难以消亡。

Java 堆中垃圾回收分区

在 Java 堆中,会将新生代分成一块较大的 Eden 区,和两块较小的 Survivor 区。在 HotPots 虚拟机中,这一比例默认为为 8:1:1.

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

垃圾回收的方式

  • 部分收集 (Partical GC):指不完整收集整个 Java 堆
    • 新生代收集 (Minor GC/Young GC):指新生代中的垃圾收集器
    • 老年代收集 (Major GC/Old GC):指老年代的垃圾收集器
    • 混合收集 (Mixed GC):指整个新生代和部分老年代的垃圾收集器(G1 收集器)
  • 整堆收集 (Full GC):整个 Java 堆的垃圾收集器

回收算法

标记-清除算法

标记清除算法会首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象

缺点:

  • 执行效率不稳定,标记和清除这两个动作的执行效率会随着对象数量的增长而降低
  • 该方法会留下大量的碎片空间
在这里插入图片描述
在这里插入图片描述
标记-复制算法

标记复制算法会将内存按照容量大小划分为相等的两块,每次只使用其中的一块,当这一块用完了,就将还活着的对象复制到另一块上,然后再把已使用过的空间清理掉。

缺点:

  • 如果内存中多数对象都是活的,这种算法会产生大量的内存间复制开销
  • 空间浪费
在这里插入图片描述
在这里插入图片描述

该算法常用于 Java 堆中新生代的垃圾回收方法。每次分配内存只使用 Eden 和 一块 Survivor 区,当进行垃圾收集时,会将 Eden 和 Survivor 区上存活的对象复制到另一块 Survivor 区上。

标记-整理算法

在对象存活较多时,就需要进行较多的复制操作,会降低回收的效率。标记整理算法是对存活的对象进行标记,然后对对象进行整理,这样既减少了复制的次数,也避免了空间的浪费。

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-12-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 垃圾回收
    • 如何判断对象已死
      • Java 中的引用
        • 垃圾回收过程
          • 方法区的垃圾回收
          • 垃圾回收算法
            • 分代收集理论
              • 回收算法
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档