Java 堆内存采用分代回收算法,因此 JVM 针对新生代和老年代提供了多种垃圾收集器。
Serial 收集器是单线程收集器,采用复制算法。
是最基本的垃圾收集器,只会使用一个 CPU 或一条线程去完成垃圾收集工作,在垃圾收集时必须停止其他工作线程知道垃圾收集结束。
单线程收集器
使用复制算法
收集时需要暂停其他所有线程
简单高效,没有线程交互开销,垃圾收集效率最高
是 JVM 在 Client 模式下默认的新生代垃圾收集器
是 Serial 收集器的老年代版本
单线程收集器
使用标记整理算法
收集时需要暂停其他所有线程
是 JVM 在 Client 模式下默认的老年代垃圾收集器
是 JVM 在 Server 模式下 CMS 的后备收集方案
ParNew 垃圾收集器是 Serial 的多线程版本,也采用复制算法,其余行为和 Serial 完全一样。
多线程收集器
使用复制算法
收集时需要暂停其他线程
默认开启和 CPU 数目相同的线程数,通过-XX:ParallelGCThreads
参数设置线程数
是 JVM 在 Server 模式下默认的新生代垃圾收集器
Prarllel Scavenge 收集器是一个新生代垃圾收集器,采用复制算法,是一个多线程的垃圾收集器,它的侧重点是程序达到可控的吞吐量,高吞吐量可以最高效率的利用 CPU 资源。
多线程收集器
使用复制算法
注重提高系统吞吐量,提高 CPU 利用率
具有自适应调节策略
Prarllel Scavenge 收集器的老年代版本,使用多线程标记整理算法。如果系统对吞吐量要求较高,可以采用 Prarllel Scavenge 与 Prarllel Old 搭配策略。
多线程收集器
使用标记整理算法
注重提高系统吞吐量
CMS 收集器是一种老年代收集器,主要目标是获得最短垃圾回收停顿时间,以获得较高的响应比,提高用户体验。使用多线程的标记清除算法。
多线程收集器
使用标记清除算法
注重缩短垃圾收集停顿时间,追求高响应比
工作机制如下:
初始标记:只标记 GC Roots 能直接关联的对象,速度快,需要暂停所有线程
并发标记:进行 GC Roots 追踪,和用户线程一起工作,不需要暂停
重新标记:修正在并发标记期间,用户线程运行而导致标记改变的对象,需要暂停所有线程
并发清除:清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停
由于耗时最长的并发标记和并发清除不需要暂停其他线程,CMS 可近似看做与用户线程并发执行。
Garbage First 垃圾收集器是目前垃圾收集器理论最前沿的成果。
G1 避免全区域垃圾收集,把堆内存划分为大小固定的几个独立区域,并跟踪这些区域的垃圾收集进度,在后台维护一个优先级列表,每次根据允许收集时间来优先回收垃圾最多的区域。
相较于 CMS,G1 有如下优势:
基于标记整理算法,不产生内存碎片
可精确控制停顿时间,在不牺牲吞吐量的前提下实现低停顿回收
收集器 | 运行模式 | 工作范围 | 算法 | 目标 | 适用场景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单CPU环境下的Client模式 |
Serial Old | 串行 | 老年代 | 标记整理 | 响应速度优先 | 单CPU环境下的Client模式、CMS的后备预案 |
ParNew | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多CPU环境时在Server模式下与CMS配合 |
Parallel Scavenge | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
Parallel Old | 并行 | 老年代 | 标记整理 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
CMS | 并发 | 老年代 | 标记清除 | 响应速度优先 | 集中在互联网站或B/S系统服务端上的Java应用 |
G1 | 并发 | Both | 复制+标记整理 | 响应速度优先 | 面向服务端应用,将来替换CMS |