全文是在阅读了《深入理解Java虚拟机》进行的摘录笔记
Serial收集器
这个收集器是一个单线程工作的收集器。采用标记-复制算法
- 使用一个收集线程去完成垃圾收集工作
- 它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束(“Stop The World”)
Serial Old收集器
Serial收集器的老年代版本,它同样是一个单线程收集器,不同的是使用标记-整理算法
ParNew收集器
实质上是Serial收集器的多线程并行版本,除了同时使用多条线程进行垃圾收集之外,其余的行为都与Serial收集器一致,也是使用标记-复制算法
Parallel Scavenge收集器
一款新生代收集器,它同样是基于标记-复制算法实现的收集器,能够并行收集的多线程。可以达到一个可控制的吞吐量(运行用户线程时间/运行用户线程时间+运行垃圾回收时间)。
- 停顿时间越短(其他收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间)
适合需要与用户交互或需要保证服务响应质量的程序 - 高吞吐量( Parallel Scavenge)
则可以最高效率地利用处理器资源,尽快完成程序的运算 任务,主要适合在后台运算而不需要太多交互的分析任务。
Parallel Old收集器
Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。“吞吐量优先”(注重吞吐量,处理器资源稀缺)的场合可以优先考虑Parallel Scavenge加Parallel Old收集器这个组 合。
以上所有的垃圾回收器新生代都是以标记-复制算法实现的,老年代都是标记-整理。
CMS收集器(老年代)
一种以获取最短回收停顿时间为目标的收集器,最短回收停顿时间,指的是Stop The World,暂停其他用户线程的时间最短。
适合以为B/S模型的服务端上,关注服务的响应速度,希望系统停顿时间尽可能短。基于标记-清除算法实现的
整个过程分为四个步骤
- 初始标记(“Stop The World”)
标记一下GC Roots能直接关联到的对象,速度很快。 - 并发标记
从GC Roots的直接关联对象开始遍历整个对 象图的过程,这个过程耗时较长但是不需要停顿用户线程。 - 重新标记(“Stop The World”)
为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。 - 并发清除
清理删除掉标记阶段判断的已经死亡的对象,不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
不足之处
- 对处理器资源非常敏感,处理器核心数>4,并发回收时垃圾收集线程只占用不超过25%的处理器运算资源,并且会随着处理器核心数量的增加而下降…在并发阶段,会因为占用了一部分线程,导致应用程序变慢,降低总吞吐量
- “并发失败”,临时启用Serial Old收集器,这样停顿时间就更长了
并发标记和并发清理阶 段,用户线程是还在继续运行的,还会伴随有新的垃圾对象不断产生,但是标记阶段已经结束了,只好留待下一次垃圾收集再清理掉。在清理垃圾的时候还要运行程序,所以在清理垃圾的过程还要预留足够的空间给程序运行,所以CMS收集器不能像其他收集器等待到老年代快被填满了再进行收集,必须多预留一部分空间以供并发清理时使用。要是预留的内存无法满足程序分配新对象的需要,就会出现一次“并发失败”(Concurrent Mode Failure),这时候虚拟机:冻结用户线程的执行,临时启用Serial Old收集器来重新进行老年代的垃圾收集, 但这样停顿时间就很长了。 - 会有大量空间碎片产生触发Full GC的产生
基于“标记-清除”算法实现的收集器,产生大量空间碎片,无法找到足够大的连续空间来分配当前对象而触发Full GC的情况
Garbage First收集器
开创了收集器面向局部收集的设计思路和基于Region的内存布局形式,主要面向服务端应用的垃圾收集器。
垃圾收集的目标范围不再是整个新生代(Minor GC)或者整个老 年代(Major GC),或者整个Java堆(Full GC)。
G1是面向堆内存任何部分来组成Region回收集进行回收(分区),衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大。
Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个 Region容量一半的对象即可判定为大对象。
让G1收集器去跟踪各个Region里面的垃 圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间,然后在后台维护一 个优先级列表,优先处理回收价值收益最大的那些Region。
问题
- Region里面存在的跨Region引用对象如何解决
使用记忆集避免全堆作为GC Roots扫描,它的每个Region都维护有自己的记忆集,记忆集会记录下别的Region指向自己的指针, - 在并发标记阶,用户线程改变对象引用关系时,必须保证其不能打破原本的对象图结构
而G1 收集器则是通过原始快照(SATB)算法来实现的 - 垃圾回收过程,用户线程新创建对象的内存分配
G1为每一个Region设 计了两个名为TAMS(Top at Mark Start)的指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配。G1收集器即默认它们是存活的,不纳入回收范围。 - 触发Full GC
与CMS中 的“Concurrent Mode Failure”失败会导致Full GC类似,如果内存回收的速度赶不上内存分配的速度, G1收集器也要被迫冻结用户线程执行,导致Full GC而产生长时间“Stop The World”。
G1收集器的运作过程
- 初始标记
仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS指针的值,让下一阶段(并发标记)用户线程并发运行时,能正确地在可用的Region中分配新对象的内存。这个阶段需要停顿线程,但耗时很短。 - 并发标记
从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆 里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以 后,还要重新处理SATB记录下的在并发时有引用变动的对象。 - 最终标记
对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的SATB记录。 - 筛选回收
负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region 构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧 Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成的。
ZGC收集器
…
合适的搭配垃圾收集器
并行和并发
- 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
- 并发(Concurrent):指用户线程与垃圾收集线程同时执行,用户程序在继续运行。
搭配组合
- Serial,Serial Old
名称 | 是否并发 | 清除算法 | 优点 | 缺点 | 适合环境 | JDK版本 |
---|---|---|---|---|---|---|
Serial | 否(串行) | 标记-复制 | 响应速度优先 | 串行,暂停工作线程 | 单CPU环境下的Client模式 | JDK1.3.1 |
Serial Old | 否(串行) | 标记-整理 | 响应速度优先 | 串行,暂停工作线程 | 单CPU环境下的Client模式、CMS的后备预案 | JDK1.3.1 |
- Serial,CMS(JDK8时声明为废弃)
名称 | 是否并发 | 清除算法 | 优点 | 缺点 | 适合环境 | JDK版本 |
---|---|---|---|---|---|---|
Serial | 否(串行) | 标记-复制 | 响应速度优先 | 串行,暂停工作线程 | 单CPU环境下的Client模式 | JDK 1 |
CMS | 是(并发) | 标记-清除 | 最短停顿时间 | 空间碎片多触发FULL GC,并发时预留空间不足,临时启用Serial Old收集器,停顿时间就更长 | 多核心CPU环境、要求停顿时间较短 | JDK 5 |
- ParNew,CMS
名称 | 是否并发 | 清除算法 | 优点 | 缺点 | 适合环境 | JDK版本 |
---|---|---|---|---|---|---|
ParNew | 否(并行) | 标记-复制 | 响应速度优先,Serial收集器的多线程并行版本 | 串行,暂停工作线程 | 多CPU环境下服务端模式下与CMS配合 | JDK1.3.1 |
CMS | 是(并发) | 标记-清除 | 最短停顿时间 | 空间碎片多触发FULL GC,并发时预留空间不足,临时启用Serial Old收集器,停顿时间就更长 | 多核心CPU环境、要求停顿时间较短 | JDK 5 |
- ParNew,Serial Old(JDK8时声明为废弃)
名称 | 是否并发 | 清除算法 | 优点 | 缺点 | 适合环境 | JDK版本 |
---|---|---|---|---|---|---|
ParNew | 否(并行) | 标记-复制 | 响应速度优先,Serial收集器的多线程并行版本 | 串行,暂停工作线程 | 多CPU环境下服务端模式下与CMS配合 | JDK1.3.1 |
Serial Old | 否(串行) | 标记-整理 | 响应速度优先 | 串行,暂停工作线程 | 单CPU环境下的Client模式、CMS的后备预案 | JDK1.3.1 |
- Parallel Scavenge,Serial Old
名称 | 是否并发 | 清除算法 | 优点 | 缺点 | 适合环境 | JDK版本 |
---|---|---|---|---|---|---|
Parallel Scavenge | 否(并行) | 标记-复制 | 可控制的吞吐量 | 串行,暂停工作线程 | 在后台运算而不需要太多交互的任务 | JDK 1.4 |
Serial Old | 否(串行) | 标记-整理 | 响应速度优先 | 串行,暂停工作线程 | 单CPU环境下的Client模式 | JDK1.3.1 |
- Parallel Scavenge,Parallel Old
名称 | 是否并发 | 清除算法 | 优点 | 缺点 | 适合环境 | JDK版本 |
---|---|---|---|---|---|---|
Parallel Scavenge | 否(并行) | 标记-复制 | 可控制的吞吐量 | 串行,暂停工作线程 | 在后台运算而不需要太多交互的任务 | JDK 1.4 |
Parallel Old | 否(并行) | 标记-整理 | 吞吐量优先 | 并行,暂停工作线程 | 注重吞吐量,处理器资源稀缺,在后台运算而不需要太多交互的任务 | JDK 6 |
- G1
名称 | 是否并发 | 清除算法 | 优点 | 缺点 | 适合环境 | JDK版本 |
---|---|---|---|---|---|---|
G1 | 是(并发) | 分区清除 | 响应速度优先 | 内存回收的速度赶不上内存分配的速度触发触发Full GC | 面向服务端应用,将来替换CMS | jdk9以后默认开启 |
- ZGC
… - Shenandoah
…