3.5 经典垃圾收集器
3.5.1 Serial收集器
- 版本: jdk1.3.1之前
- 收集区域:新生代
- 收集方式:单线程收集
- 收集算法:标记复制
- 执行过程中需要STW
- Serial收集器对于运行在客户端模式下的虚拟机来说是一个很好的选择
- 优点
- 简单高效
- 所有收集器里面内存消耗最少的
- 无线程交互开销,在单核处理器和小内存管理(200M左右)效率较高
- 缺点
- 单线程
- 管理大内存的时候效率极低,导致STW时间过长
3.5.2 ParNew收集器
- 收集区域:新生代
- 收集算法:标记复制
- 收集方式:多线程并行(实质上是Serial收集器的多线程并行版本,除此之外几乎一模一样)
- 可以与CMS收集器配合工作
3.5.3 Parallel Scavenge收集器
- openJDK8默认收集器
- 收集区域:新生代
- 收集算法:标记复制
- 收集方式:多线程并行
- 关注点:吞吐量,又被成为吞吐量优先收集器
- 吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)
- 吞吐量控制参数:
- -XX:MaxGCPauseMillis 控制最大GC时间
- -XX:GCTimeRatio 设置吞吐量大小,GC时间比例
3.5.4 Serial Old收集器
- 收集区域:老年代
- 收集算法:标记整理
- 收集方式:单线程
- 在JDK 5以及之前的版本中与Parallel Scavenge收集器搭配使用
- 作为CMS 收集器发生失败时的后备预案
3.5.5 Parallel Old收集器
- 收集区域:老年代
- 收集算法:标记整理
- 收集方式:多线程并行
- 在JDK 6 之后提供,Parallel Scavenge的老年代版本。
3.5.6 CMS收集器(Concurrent Mark Sweep)
- 收集区域:老年代
- 收集算法:标记清除 + 标记整理 ,并使用Serial Old兜底
- 收集方式:多线程并发,(并发:垃圾回收和用户线程同时执行)
- 优点
- 并发收集
- 低停顿
- 缺点
- 并发过程中占用用户线程,导致吞吐量降低,CMS默认启动的回收线程数是(处理器核心数量 +3)/4,也就是说,如果处理器核心数在四个或以上,并发回收时垃圾收集线程只占用不超过25%的 处理器运算资源,并且会随着处理器核心数量的增加而下降。
- 无法处理“浮动垃圾”,而浮动垃圾过多会启用Serial Old进行收集,Serial Old处理大内存的收集,停顿时间是相当久的。
- 由于使用标记清除算法进行收集清除,导致大量内存碎片,不得不对其进行整理,而整理牵扯到存活对象的移动就需要进行STW,又增加了停顿时间。
浮动垃圾:在CMS的并发标记和并发清理阶 段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,但这一部分 垃圾对象是出现在标记过程结束以后,CMS无法在当次收集中处理掉它们,只好留待下一次垃圾收集 时再清理掉。这一部分垃圾就称为“浮动垃圾”。
3.5.7 Garbage First收集器(G1)
- 目标:在延迟可控的情况下获得尽可能高的吞吐 量
- 里程碑:开创了收集 器面向局部收集的设计思路和基于Region的内存布局形式。
- 收集范围:面向堆内存任 何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是G1收集器的Mixed GC模式。
- 由于Region过多,会导致记忆集占用内存过大。根据经验,G1至少要耗费大约相当于Java堆容量10%至20%的额 外内存来维持收集器工作。
- 可由用户指定停顿时间: -XX:MaxGCPauseMillis 默认200ms
- 优点
- 可指定停顿时间
- 低延迟,高吞吐量
- Region布局设计,收集速度极快
- 缺点
- 多个Region之间跨代引用过多,记忆集占用空间过大
Region布局:G1不再坚持固定大小以及固定数量的 分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。