JVM学习之GC算法介绍

143 阅读6分钟

一、垃圾标记算法:引用计数算法

0、运行时数据区的GC和OOM

  • GC发生区域:堆、方法区
  • OOM发生区:堆、方法区、栈

1、什么是引用计数法?

  • 简单来说,就是看对象被引用的情况。如果被引用0次,就认为是垃圾;如果大于0次,就i不是垃圾

2、优缺点

优点:

1)实现简单
(2)垃圾对象便于识别,查看引用计数就行
(3)判断效率高,回收没有延迟

缺点:

1)需要单独的字段存储引用计数,增加存储空间的开销
(2)每次赋值都需要更新引用计数,增加时间开销
(3)没有办法解决循环引用

二、垃圾标记算法:可达性分析算法

1、什么是可达性分析算法?

  • 以根对象集合为起始点,按照从上到下的方式搜索被根对象集合所连接的目标对象是否可达。简单来说,就是挑一些对象作为根节点,然后从根节点出发去查找与子节点的引用关系,类似在树上进行查找标记。

2、为什么选择?

  • 主要是能够解决循环引用

3、java中哪些可以作为GC Roots?

  • 虚拟机栈中引用的对象

  • 本地方法栈JNI引用的对象

  • 方法区中类静态属性引用的对象

  • 方法区常量池引用的对象

  • 所有被synchronized持有的对象

总结来说就是围绕堆空间去引用堆中对象的数据区。

4、注意点

  • 在进行可达性分析时,需要一个稳定的快照版本,这个其实就是要求对象保持一致性。之所以这样要求,是想在分析时,保持引用关系静态不变。

三、对象的finalization机制

1、啥是这个机制?

  • 没有引用指向对象时,jvm会去回收这个对象,在回收对象前就会去调用finalize()方法。

2、一些建议

  • 这个方法大家还是不要自己去手动调用了

3、有啥用?

  • 处理一些资源,比如流啥的
  • 可以在这个方法中再次去引用某个对象,这样这个对象就不会被回收了

4、系统怎么做的?

  • 一般会有一个系统级的线程去执行这个finalize()方法,这个线程的级别比较低,啥时候去调用也不能确定,哈哈哈!

5、从这个finalization机制去分类对象的状态

前面说过可以在finalize()方法去重新引用对象,这样就可以对对象进行状态分类:

  • 可触及的对象:就是通过可达性分析引用可以到达的对象
  • 可复活的对象:就是对象的引用被释放,但是可以在finalize()方法中可以被重新引用
  • 不可触及的对象:去调用了finalize()方法,但是没有复活,这个时候就真的不能再被复活了,被判定为死刑的对象。

6、注意点

  • finalize()这个对象只能被调用一次

四、MAT与JProfiler的GC Roots溯源

五、垃圾清除算法:标记-清除算法

1、简单介绍

  • 标记:从根节点开始,标记被引用的对象。一般在对象头中记录可达对象
  • 清除:收集器对堆内存从头到尾进行线性遍历,如果发现某个对象在对象头中没有标记为可达对象,则将其回收

2、优缺点

优点:

  • 算法简单,也好理解

缺点:

  • 效率不算高,主要问题在两次遍历对象,特别是第二次遍历
  • 在GC时,需要STW
  • 回收后,容易产生内存碎片;由于有碎片,所以内存分配会不规整,要使用空闲列表法去分配对象内存

六、垃圾清除算法:复制算法

1、简单介绍

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

  • 新生代的s0,s1区的垃圾回收算法就是这个

2、优缺点

优点:

  • 没有标记和清除,所以效率高
  • 复制过去以后保证空间的连续性,不会出现碎片问题

缺点:

  • 需要两倍的内存空间

  • 如果系统中的垃圾对象不多,复制算法效果就不是很好,因为每次都是将绝大多数的对象又复制一遍

七、垃圾清除算法:标记-压缩算法

1、简单介绍

  • 是在标记清除算法的基础上做的优化,主要是为了解决内存碎片的问题

  • 标记:从根节点开始标记所有被引用的对象

  • 压缩:将所有的存活对象压缩到内存的一端,按照顺序排放

  • 经过压缩的对象,当需要对新的对象分配内存时,需要使用指针碰撞法

2、优缺点

优点:

  • 解决了标记清除算法的内存碎片的问题,同时也解决了复制算法的需要2倍内存的问题

缺点:

  • 三个算法比较是效率最低的,因为涉及到碎片清除和对象移动
  • 对象移动过程中,需要暂停用户程序

3、三种算法的比较

标记清除复制算法标记压缩
速度中等最块最慢
空间开销少,但有碎片2倍空间少,没有碎片
移动对象不移动

八、垃圾清除算法:分代收集算法

1、简单介绍

  • 针对堆空间分代的思想产生的算法,需要根据代的特性,堆每个代采用不同的算法
  • 年轻代:
    • 内存区域较小,对象生命周期短、存活率低,回收频率高,适合使用复制算法
  • 老年代:
    • 内存区域大,对象生命周期长、存活率高、回收频率相对较低,一般采用标记清除算法或标记整理算法

九、垃圾清除算法:增量收集算法

1、简单介绍

  • 这个算法主要是为了解决STW响应时间长的问题,用户线程挂起的问题
  • 尝试在标记清除和标记压缩算法的基础上,采用并发的方式,是系统线程和用户线程并发执行

2、优缺点

缺点:

  • 由于尝试使用并发的方式,让用户线程和系统线程交替执行,线程切换使得系统资源的消耗,导致系统吞吐量的下降

十、垃圾清除算法:分区算法

1、简单介绍

  • 主要是G1垃圾收集器使用这个算法
  • 主要是将堆分成若干区域,每个区域套用分代的思想,也表示Eden区、S0区、S1区、老年代、永久代(元空间),这样在进行垃圾回收的时候,处理的是较小的区域,效率就提高了