一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
垃圾检测算法
引用计数法
工作原理:
- 遍历堆中的全部实例,实例每被引用一次计算器+1,不再被引用计数器-1,遍历完找到那些计算器为0的对象的过程。(计数器为0的被视为垃圾)
存在的问题:
- 如果两个对象循环引用的话,就无法回收
- 找垃圾的时候每次都有遍历所有实例会损耗性能
可达性分析法
工作原理:
- 从GC Roots(GC起点)出发,遍历实例,能访问到的就不是垃圾,访问不到的就是垃圾
哪些对象可以作为GC ROOTS
- 局部变量表:正在执行的函数的参数,临时变量,临时值
- 方法区中的静态变量:类中的静态变量
- 方法区中的常量池:常量池中的常量引用实例
- 本地方法栈中的变量:JNI调用Native方法所引用的实例
- 同步锁持有的对象
垃圾回收算法
复制算法
复制算法的优点是保证空间连续,算法实现逻辑相对简单,缺点是浪费空间
标记清除
标记清除算法的优点是算法效率高,实现相对简单,缺点是不能保证空间的连续性。
标记整理
标记整理算法的优点是能够保证空间连续性,缺点是效率低于标记清除,算法实现难度相对较大。
HotSpot中的垃圾回收器
串行回收器(Client模式下默认垃圾回收器)
Serial
- 是jdk1.3之前,年轻代唯一的回收器
- 采用的垃圾回收算法是复制算法
- 负责Young GC
Serial Old
- 采用的垃圾回收算法是标记整理算法
- 负责Old GC
并行回收器
并行回收器有
- ParNew ,
- Parallel Scavenge 采用复制算法 ,作用在年轻代
- parallel old 采用标记整理算法,作用在老年代
相比串行的提升了GC的吞吐量
Parallel 是Java8默认的回收器
并发回收器
- G1是java9默认的回收器,不再基于分代回收模型
- ZGC是在java11引入,不再基于分代回收模型
- CMS主要用于老年代,也可以用于年轻代
CMS(采用标记清除算法)
CMS的三次标记
- 初始标记:会STW,但是只标记到GC Roots直接引用的实例(第一级),所以STW很短暂
- 并发标记:从初始标记的对象开始,遍历全部关联实例,耗时最久但可以与用户线程并行执行,不会执行STW
- 重新标记:STW 修正并发标记时,用户线程导致标记不准确的情况,也就是脏实例的问题
G1分区回收
- 将内存划分为多个大小相等的区里区域(Region),这些区域包含了逻辑上的年轻代和老年代
- Humongous用来专门存储大实例
- 区域之间时复制算法,但整体可以看作是标记整理算法
- 可以只针对部分区域进行垃圾回收,所以可以与用户线程交替进行,缩短STW
- 可以设置一定时间内,允许垃圾回收的时间,来实现可预测的STW