前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM-4. 垃圾收集算法

JVM-4. 垃圾收集算法

作者头像
悠扬前奏
发布2019-05-28 12:51:53
4170
发布2019-05-28 12:51:53
举报

三个问题:

  • 那些内存需要回收
  • 什么时候回收
  • 如何回收

程序计数器,虚拟机栈,本地方法栈生命周期和线程相同;栈中的栈帧随着方法进入和退出进行入栈和出栈操作。栈帧需要内存基本上在编译器可知,因此一般这几个区域的内存分配和回收都具备已知性,不多考虑回收的问题。 而堆中,一个接口的实现类需要的内存不一样,一个方法的多个分支需要的内存也不一样,只有在程序运行时才能知道分配那些内存。因此垃圾回收器关注的主要是这部分内存

1. 哪些内存需要回收

1.1 引用计数法

给对象添加一个引用器,有一个地方引用就加1,引用失效就减1;任何时刻计时器为0的对象就不被使用。

  • 实现简单,效率高
  • 很难解决对象之间相互循环引用的问题
  • Java虚拟机没有使用这种方法

1.2 可达性分析(Reachability Analysis)算法

通过一系列被称为“GC Roots”的对象作为起始点,从节点开始搜索,搜索经过的路径被称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(GC Roots到这个对象不可达),证明该对象不可用。

  • Java虚拟机使用了这种方法
  • Java虚拟机中作为GC Roots的对象包括:
    • 虚拟机栈(栈帧中本地对象变量表)中引用的对象
    • 方法区中静态属性应用的对象
    • 方法区中常量引用的对象
    • 本地方法栈中JNI(即Native方法)引用的对象

1.3 优化的引用

未优化的引用:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,则表示这块内存代表这一个引用。 希望的引用:当内存空间充足,留在内存中;如果内存空间在进行垃圾回收之后还是紧张,放弃这些对象。 JDK1.2之后的优化,将引用分为以下四种:

  • 强引用(Strong Reference):例如"Object obj = new Object()",只要强引用存在,GC永远不会回收被引用的对象。
  • 软引用(Soft Reference):用来描述还有用但非必须的对象。在OOM之前,将对象列入回收范围之中进行第二次回收,如果此次回收还是没有足够内存,才抛出OOM。有SoftReference类实现软引用
  • 弱引用(Weak Reference):用来描述非必须对象,但是比软引用更弱,弱引用的对象只生存到下一次GC之前,无论GC时内存是否足够,都会被回收。有WeakReference来实现弱引用。
  • 虚引用(Phantom Reference):最弱。对象是否有虚引用存在,不会影响其生存时间,也无法通过虚引用来获得对象实例。其唯一目的就是对象被GC之前收到一个系统通知。有PhantomReference来实现虚引用。

1.4 方法区的回收

  • 方法区(永久代)的回收效率较低
  • 方法区的垃圾回收主要在两部分:
    • 废弃常量:和回收Java堆中对象很类似,以是否有引用的方式判断。
    • 无用的类:同时满足三个条件:
      • 该类所有的实例都已经被回收,堆中不存在该类的任何实例
      • 加载该类的ClassLoader已经被回收
      • 该类对应的java.lang.Class对象已经没有在任何地方被应用,无法再任何地方通过反射访问该类的方法

2. 何时回收

在可达性分析算法中得到的对象需要进过两次标记:

  • 在可达性分析后发现没有与GC Roots的引用链,被第一次标记并筛选此对象有否必要执行finalize()方法
  • 如果对象没有覆盖finalize()方法,或者finalize()方法被调用过,虚拟机都是为没有必要执行,进行回收,注意即使覆盖了finalize()方法,它也只执行一次!

不建议使用finalize():1. 不稳定,不能确定何时执行;2. 方法中的工作可以在try/finally块中进行。

3. GC算法(如何回收)

3.1 标记 - 清除(Mark-Sweep)

先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。 不足在于:

  • 效率低
  • 会产生大量不连续的空间。这样账号后程序的运行需要分配较大对象时,无法找到足够的连续内存会更频繁的触发GC

3.2 复制算法(Copying)

将内存按照容量分为大小相同的两块,每次只使用其中一块,当这一块内存使用完了,将存活的对象复制到另一块上面,然后把用过的内存空间一次清掉。

  • 运行高效
  • 设计使用内存只有一半

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

标记出所有需要回收的对象,完成后所有存活的对象往一侧移动,然后清理掉端边界以外的内存。

3.4 分代收集算法(Generational Collection)

根据对象存活周期将不同将算法划分为几块(一般分为新生代和老年代),根据年代特点选择合适的收集算法:

  • 新生代中每次垃圾回收有大量对象回收,只有少量保留,就选用复制算法,只需要少量存货对象的复制成本。
  • 老年代中对象存活概率高,没有额外空间进行分配担保,采用“标记-清理/整理”算法。

4. HotSpot的GC

4.1 枚举根节点

可达性分析需要用到GC Roots,存在的问题有两个:

  • 方法区很大的时候,GC Roots节点检查过程需要时间
  • 分析期间执行系统需要冻结

HotSpot对问题的解决(准确式GC): 使用OopMap的数据结构,在类加载完成时,把对象内多少偏移量对应着什么类型的数据,在JIT编译(just in time, 即时编译技术,将字节码编译成本机机器代码)过程中,也对特定位置记录下栈寄存器中那些位置是引用。这样,虚拟机是直接知道哪个地方存放着对象引用的。在执行系统停顿后,不需要检查完所有执行上下文和全局引用位置。

4.2 安全点

OopMap可以帮助HotSpot快而准的完成GC Roots的枚举,但是出现问题: 引起OopMap内容变化(引用关系变化)指令很多,都生成对应的OopMap会提高GC的空间成本。 所以,HotSpot只在特定位置(安全点,Safepoint)生成了OopMap。

如何选定安全点呢? “是否具有让程序长时间执行的特征”——最明显就是指令序列复用,如方法调用,循环调转,异常跳转等功能指令会产生安全点。

如何在GC是让所有线程(不包括JNI线程——Java Native Interface,实现了Java和其他语言的通信)都等到最近的安全点再停顿呢?

  • 抢先式中断(Preemptive Suspension),不需要线程的执行代码主动配合,GC时所有线程全部中断,如果线程中断点不是安全点,就恢复线程,让它运行到安全点上。没有虚拟机采用这种方式。
  • 主动式中断(Voluntary Suspension),不直接对线程进行操作,设置一个标志,各线程主动轮询这个标志,发现中断标志为真就主动中断挂起。轮询标志点包括安全点和创建对象需要分配内存的点。

4.3 安全区域

安全点遇到的问题:线程处于Sleep,Blocked等状态,无法走到安全点响应JVM的中断请求。 通过安全区域(Safe Region)解决:在一段代码中,引用关系不会发生变化,在这个区域中任意地方GC都是安全的。

  1. 线程执行到这些代码,先标记自己进入了Sage Region。
  2. JVM在GC时不处理标记为Safe Region状态的线程。
  3. 线程离开Safe Region时检查JVM是否完成了根节点枚举(或者GC全过程),如果完成了。线程继续执行,否则等待知道收到可以安全离开Sage Region信号为止。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.04.08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 哪些内存需要回收
    • 1.1 引用计数法
      • 1.2 可达性分析(Reachability Analysis)算法
        • 1.3 优化的引用
          • 1.4 方法区的回收
          • 2. 何时回收
          • 3. GC算法(如何回收)
            • 3.1 标记 - 清除(Mark-Sweep)
              • 3.2 复制算法(Copying)
                • 3.3 标记-整理算法(Mark-Compact)
                  • 3.4 分代收集算法(Generational Collection)
                  • 4. HotSpot的GC
                    • 4.1 枚举根节点
                    • 4.2 安全点
                      • 4.3 安全区域
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档