Java虚拟机--垃圾收集器--parallel Scavenge 与 Parallel Old 收集器
Parallel Scavenge收集器
Parallel Scavenge收集器也是一款新生代收集器, 它同样是基于标记-复制算法实现的收集器, 也是能够并行收集的多线程收集器.
Parallel Scavenge 收集器的目标是达到一个可控制的吞吐量(Throughput). 所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗时间的比值, 即: 吞吐量=运行用户代码时间/(运行用户代码时间+运行垃圾收集时间).
Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量, 分别是控制最大垃圾收集停顿时间的 -XX:MaxGCPauseMillis 参数以及直接设置吞吐量大小的 -XX:GCTimeRatio 参数.
-XX:MaxGCPauseMillis 参数允许的值是一个大于 0 的毫秒数, 收集器将尽力保证内存回收花费的时间不超过用户设定值. 不过大家不要异想天开地认为如果把这个参数的值设置得更小一点就能使得系统的垃圾收集速度变得更快, 垃圾收集停顿时间缩短是以牺牲吞吐量和新生代空间为代价换取的: 系统把新生代调得小一些, 收集300MB新生代肯定比收集500MB快, 但这也直接导致垃圾收集发生得更频繁, 原来10秒收集一次、每次停顿100毫秒, 现在变成5秒收集一次、每次停顿70毫秒. 停顿时间的确在下降, 但吞吐量也降下来了.
-XX:GCTimeRatio 参数的值则应当是一个大于 0 小于 100 的整数, 也就是垃圾收集时间占总时间的比率, 相当于吞吐量的倒数. 譬如把此参数设置为 19, 那允许的最大垃圾收集时间就占总时间的 5% (即1/(1+19), 默认值为 99, 即允许最大1%(即1/(1+99))的垃圾收集时间.
Parallel Scavenge 收集器也经常被称作“吞吐量优先收集器”. 除上述两个参数之外, Parallel Scavenge 收集器还有一个参数 -XX:+UseAdaptiveSizePolicy 值得我们关注. 这是一个开关参数, 当这个参数被激活之后, 就不需要人工指定新生代的大小(-Xmn)、Eden 与 Survivor 区的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了, 虚拟机会根据当前系统的运行情况收集性能监控信息, 动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量. 这种调节方式称为垃圾收集的自适应的调节策略.
Parallel Old 收集器
Parallel Old 是 Parallel Scavenge 收集器的老年代版本, 支持多线程并发收集, 基于标记-整理算法实现. 这个收集器是直到 JDK 6 时才开始提供的, 在此之前, 新生代的 Parallel Scavenge收集器一直处于相当尴尬的状态, 原因是如果新生代选择了 Parallel Scavenge 收集器, 老年代除了 Serial Old(PS MarkSweep)收集器以外别无选择, 其他表现良好的老年代收集器, 如CMS无法与它配合工作. 由于老年代 Serial Old 收集器在服务端应用性能上的“拖累”, 使用Parallel Scavenge 收集器也未必能在整体上获得吞吐量最大化的效果. 同样, 由于单线程的老年代收集中无法充分利用服务器多处理器的并行处理能力, 在老年代内存空间很大而且硬件规格比较高级的运行环境中, 这种组合的总吞吐量甚至不一定比ParNew加CMS的组合来得优秀.
UseParallelGC: JDK9 之前虚拟机运行在 Server 模式下的默认值, 打开磁开关后, 使用 ParallelScavenge + Serial Old(PS MarkSweep)的收集器组合进行内存回收.
UseParallelOldGC: 打开此开关后, 使用 Parallel Scavenge + Parallel Old 的收集器组合进行内存回收.