常见的几种JAVA垃圾收集器

这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

5. 垃圾收集器

垃圾收集算法就像是 Java 中的接口一样,而垃圾收集器是接口的具体实现。所以,不同的厂商,不同版本的虚拟机实现的方式都有所不同。甚至是很大的差别。

下图是常见的 HotSpot 虚拟机中的垃圾收集器。

垃圾收集器

其中,新生代有 Serial、ParNew、Parallel Scavenge,老年代包括 CMS、MSC、Parallel old,收集器之间的连线说明两者可以搭配使用。

5.1 Serial 收集器

Serial 是最基本,历史最悠久,也是最简单的一个收集器。它是一个单线程的收集器。当它开始进行垃圾回收时,必须暂停其他所有工作线程,直到收集结束。虽然在垃圾回收时会发生“Stop The World”导致用户体验不佳,但是 Serial 收集器还是有优点的,在单CPU环境下 Serial 收集器由于没有线程操作的开销,只做垃圾收集,所以效率远高于其他收集器。

5.2 ParNew 收集器

ParNew 收集器是 Serial 收集器的一个并行版本,与 Serial 的区别在于 STW 期间并行进行垃圾收集。它是大多数 Server 模式下新生代首选的收集器,一个比较重要的原因是,目前只有 ParNew 和 Serial 能与老年代的 CMS 收集器使用。也就是说如果老年代的收集器你选择了 CMS 新生代的收集器就只能从这两者中选择一个。

需要注意的是,在单CPC环境中,由于 ParNew 收集器存在与线程交互的开销,所以效率一定没有 Serial 收集器高。 甚至在两个 CPU 的情况下都不能百分之百的保证可以高于 Serial。当然,随着 CPU 的数量增多, ParNew 收集器的性能会越来越好。

5.3 Parallel Scavenge 收集器

Parallel Scavenge 收集器是新生代的收集器,采用的是复制算法,并行收集。功能和 ParNew 很类似。其他收集器的关注点都是如何尽可能的缩短 STW 的时间,而 Parallel Scavenge 收集器的目标是控制 STW 占用时间的百分比。这个百分比称为吞吐量。其实就是 用户代码的执行时间与CPU的总执行时间的比值。比如,JVM 总共运行了 100 分钟,而 GC 用了 2 分钟,那么吞吐量就是 98%( 98/(98+2) )。使用 Parallel Scavenge 收集器,你可以通过“-XX:GCTimeRatio“参数设置吞吐量的大小。

GCTimeRatio 参数的值是一个(0,100)闭区间的整数值,含义是垃圾收集时间的占比。相当于吞吐量的倒数。默认值时 99,即最大允许 1%( 1/(1+99),的时间用来做垃圾收集。

还可以通过”-XX:MaxGCPauseMillis“ 参数设置每次 GC 的周期,收集器将尽可能的保证垃圾收集的时间不超过该值。不过,不要认为将该值设置的稍微小一点就能使得 GC 的时间更快。GC 的停顿时间是通过牺牲新生代的空间来换来的。新生代空间小了,有可能导致 GC 的次数增多,总体算下来吞吐量有可能不增反减。

5.4 Serial Old 收集器

Serial Old 收集器是 Serial 收集器的老年代版本,同样是单线程的,使用的是”标记-整理算法“。它的两个主要用途是,一个用于 Client 端。另一个是在 Server 端用于 CMS 收集器的后备预案(详见 CMS 收集器)。

5.5 Parallel Old收集器

同样,Parallel Old 是 Parallel Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法”。需要注意的是,如果老年代使用 Parallel Old 那么新生代就只能使用 Parallel Scavenge 与之配合。在某些吞吐量优先的场景下可以考虑这种组合。

おすすめ

転載: juejin.im/post/7034487823386279966