共计 2379 个字符,预计需要花费 6 分钟才能阅读完成。
HotSpot 虚拟机提供了多种垃圾收集器,每种收集器都有各自的特点,尽管咱们要对各个收集器进行比拟,但并非为了挑选出一个最好的收集器。咱们抉择的只是对具体利用最合适的收集器。
新生代垃圾回收器(单线程)
Serial 垃圾收集器(单线程)
只开启一条 GC 线程进行垃圾回收,并且在垃圾收集过程中进行所有用户线程,即 Stop The World。
个别客户端利用所需内存较小,不会创立太多对象,而且堆内存不大,因而垃圾收集器回收工夫短,即便在这段时间进行所有用户线程,也不会感觉显著卡顿。因而 Serial 垃圾收集器适宜客户端应用。
因为 Serial 收集器只应用一条 GC 线程,防止了线程切换的开销,从而简略高效。
ParNew 垃圾收集器(多线程)
ParNew 是 Serial 的多线程版本。由多条 GC 线程并行地进行垃圾清理。但清理过程仍然须要 Stop The World。
ParNew 谋求低进展工夫,与 Serial 惟一区别就是应用了多线程进行垃圾收集,在多 CPU 环境下性能比 Serial 会有肯定水平的晋升;但线程切换须要额定开销,因而在复线 CPU 环境中体现不如 Serial。
Parallel Scavenge 垃圾收集器(多线程)
Parallel Scavenge 和 ParNew 一样,都是多线程、新生代垃圾收集器。然而两者有微小的不同点:
- Parallel Scavenge:谋求 CPU 吞吐量,可能在较短的工夫内实现指定工作,因而适宜没有交互的后盾计算。
- ParNew:谋求升高用户进展工夫,适宜交互式利用。
吞吐量 = 运行用户代码的工夫 / (运行用户代码的工夫 + 垃圾收集工夫)
谋求高吞吐量,能够通过缩小 GC 履行理论工作的工夫,然而,仅仅偶然运行 GC 意味着每当 GC 运行时将有许多工作要做,因而在此期间积攒在堆内存中的对象数量很高。单个 GC 须要花更多的工夫来实现,从而导致更高的暂停工夫。而思考到低暂停工夫,最好频繁运行 GC 以便疾速实现,反过来又导致吞吐量降落。
- 通过参数 -XX:GCTimeRadio 设置垃圾回收工夫占总 CPU 工夫的百分比。
- 通过参数 -XX:MaxGCPauseMillis 设置垃圾处理过程最久进展工夫。
- 通过命令 -XX:+UseAdaptiveSizePolicy 开启自适应策略。咱们只有设置好堆的大小和 MaxGCPauseMillis 或 GCTimeRadio,收集器会主动调整新生代的大小、Eden 和 Survivor 的比例、对象进入老年代的年龄,以最大水平上靠近咱们设置的 MaxGCPauseMillis 或 GCTimeRadio。
老年代垃圾收集器
Serial Old 垃圾收集器(单线程)
Serial Old 收集器是 Serial 的老年代版本,都是单线程收集器,只启用一条 GC 线程,都适宜客户端利用。他们惟一的区别就是:Serial Old 工作在老年代,应用“标记 - 整顿”算法;Serial 工作在新生代,应用“复制”算法。
Parallel Old 垃圾回收器(多线程)
Parallel Old 收集器是 Parallel Scavenge 的老年代版本,谋求 CPU 吞吐量。
CMS 垃圾收集器
CMS(Concurrent Mark Sweep,并发标记革除)收集器是以获取最短回收进展工夫为指标的收集器(谋求低进展),它在垃圾收集是是的用户线程和 GC 线程并发执行,因而在垃圾收集过程中用户也不会感到显著卡顿。
- 初始标记:Stop The World,仅应用一条初始标记线程对所有与 GC Roots 间接关联的对象进行标记。
- 并发标记:应用多条标记线程,与用户线程并发执行。此过程进行可达性剖析,标记处所有废除对象。速度很慢。
- 从新标记:Stop The World,应用多条标记线程并发执行,将方才并发标记过程中呈现的废除对象标记进去。
- 并发革除:只应用一条 GC 线程,与用户线程并发执行,革除方才标记的对象。这个过程十分耗时。
并发标记与并发革除过程耗时最长,且能够与用户线程一起工作,因而,总体上说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。
对于产生碎片空间的问题,能够通过开启 -XX:+UserCMSCompartAtFullCollection,在每次 Full GC 实现后都会进行一次内存压缩整顿,将零散在各处的对象整顿到一块。设置参数
-XX:CMSFullGCsBeforeCompaction 通知 CMS,通过了 N 次 Full GC 之后在进行一次内存整理。
G1 通用垃圾收集器
G1 是一款面向服务端利用的垃圾收集器,它没有新生代和老年代的概念,而是将堆划分为一块块独立的 Region。当要进行垃圾收集时,首先预计每个 Region 中垃圾的数量,每次都从垃圾回收价值最大的 Region 开始回收,因而能够取得最大的回收效率。
从整体上看,G1 是基于“标记 - 整顿”算法实现的收集器,从部分(两个 Region 之间)上看是基于“复制”算法实现的,这意味着运行期间不会产生内存空间碎片。
【思考】一个对象和它外部所援用的对象可能不在同一个 Region 中,那么当垃圾回收时,是否须要扫描整个堆内存能力残缺的进行一次可达性剖析?
【解】并不需要!每个 Region 都只有一个 Remembered Set,用于记录本区域中所有对象援用的对象所在的的区域,进行可达性剖析时,只有在 GC Roots 中再加上 Remembered Set 即可避免对整个堆内存的遍历。
如果不计算保护 Remember Set 的操作,G1 收集器的工作过程分为以下几个步骤:
- 初始标记:Stop The World,仅实用一条初始标记线程所有与 GC Roots 间接关联的对象进行标记。
- 并发标记:会用一条标记线程与用户线程并发执行。此过程进行可达性剖析,速度很慢。
- 最终标记:Stop The World,实用多条标记线程并发执行。
- 筛选回收:回收废除对象,此时也要 Stop The World,并应用多条筛选回收线程并发执行。