总述
基于jvm垃圾收集算法的理论基础,不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并且一般都会提供参数供用户根据自己的应用特点和要求组合出各个年代所使用的收集器。
HopSpot虚拟机的垃圾收集器如下图所示:
如果两个收集器之间存在连线,就说明它们可以搭配使用
虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器
虚拟机追求的提升,主要都在以下几个方向做努力:
缩短停顿时间:停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。
提高吞吐量:高吞吐量可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间/(运行用户代码时间 +垃圾收集时间),虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%.
注意
先解释两个名词:并发和并行。这两个名词都是并发编程中的概念,在谈论垃圾收集器的上下文语境中,它们可以解释如下:
● 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
● 并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。
接下来逐一介绍这些收集器的特性、基本原理和使用场景。
Serial收集器
是java很古老的收集器,不过虽然古老,但是简单高效,依旧是Client模式下的默认新生代收集器。
特点:
单线程工作,并且工作时必须停止所有线程。
优点:
单线程效率最高 应用场景:
Client模式新生代首选。
ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本。
优点:
除了Serial收集器外,目前只有它能与CMS收集器配合工作
多线程时,支持并行执行垃圾收集,比Serial效率高
应用场景:
Server模式新生代首选,(于效率无关,主要是能和CMS一起用)
Parallel Scavenge收集器
它也经常称为“吞吐量优先”收集器。算法与ParNew基本相同,但是提高效率的方式注重提高吞吐量。
为什么高吞吐量和短停顿时间不可兼得?
GC停顿时间缩短是以牺牲吞吐量和新生代空间来换取的:系统把新生代调小一些,收集300MB新生代肯定比收集500MB快吧,这也直接导致垃圾收集发生得更频繁一些,原来10秒收集一次、每次停顿100毫秒,现在变成5秒收集一次、每次停顿70毫秒。停顿时间的确在下降,但吞吐量也降下来了。
Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。
优点:
可控制的吞吐量
应用场景:
后台运算而不需要太多交互的场景
Serial Old收集器
老年代
单线程
使用“标记-整理”算法
应用场景:
Client模式下老年代
Server模式下,它主要还有两大用途:一种用途是在JDK 1.5以及之前的版本中与Parallel Scavenge收集器搭配使[插图],另一种用途就是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用