17、JVM 调优实战 - 深入理解JVM的年轻代回收器ParNew是如何工作的?

1. 最常用的新生代垃圾回收器: ParNew

在没有G1垃圾回收器之前,线上系统使用的都是ParNew垃圾回收器作为新生代的垃圾回收器。

即使现在有了G1,很多线上系统还是用的ParNew

通常运行在服务器上的Java系统,都可以充分利用服务器的多核CPU的优势。假设你的服务器是4核CPU,如果对新生代垃圾回收的时候,仅仅使用单线程进行垃圾回收,就会导致没法充分利用CPU资源。

 

如上图,现在在垃圾回收的时候,都把系统程序所有的工作线程全部停掉了,就一个垃圾回收线程在运行。

那么此时4核CPU的资源根本没法充分利用,理论上4核CPU可以支持4个垃圾回收线程并行执行,可以提升4倍的性能!

所以说,新生代的ParNew垃圾回收器主打的就是多线程垃圾回收机制,另外一种Serial垃圾回收器主打的是单线程垃圾回收,他们俩都是回收新生代的,唯一的区别就是单线程和多线程的区别,但是垃圾回收算法是完全一样的。

 

如上图,ParNew垃圾回收器在合适的时机执行Minor GC的时候,就会把系统程序的工作线程全部停掉,禁止程序继续运行创建新的对象,然后自己就用多个垃圾回收线程去垃圾回收,回收的机制和算法就跟之前说的是一样的。

2. 如何为线上系统指定使用ParNew垃圾回收器?

在启动系统的时候如果要指定使用ParNew垃圾回收器,使用 “-XX:+UseParNewGC” 选项,只要加入这个选项,JVM启动之后对新生代进行垃圾回收的,就是ParNew垃圾回收器了。

3. ParNew垃圾回收器默认情况下的线程数量

在指定了使用ParNew垃圾回收器之后,它默认给自己设置的垃圾回收线程的数量就是跟CPU的核数是一样的。

比如线上机器用的是4核CPU,那么此时ParNew的垃圾回收线程数就会是4个线程。一般不用手动去调节。

如果一定要自己调节ParNew的垃圾回收线程数量,也是可以的,使用 “-XX:ParallerlGCThreads” 参数即可,通过它可以设置线程的数量。

4. 思考题1

主要有两个问题:

1、 到底是用单线程垃圾回收好,还是多线程垃圾回收好?

2、 到底是Serial垃圾回收器好还是ParNew垃圾回收器好?

启动系统的时候可以区分服务器模式和客户端模式,如果启动系统的时候加入 “-server” 就是服务器模式,如果加入 “-client” 就是客户端模式

他们的区别就是,如果你的系统部署在比如4核8G的Linux服务器上,那么就应该用服务器模式,如果你的系统是运行在比如Windows上的客户端程序,那么就应该是客户端模式。

那么服务器模式和客户端模式的区别是啥

服务器模式通常运行我们的网站系统、电商系统、业务系统、APP后台系统之类的大型系统,一般都是多核CPU。

所以此时如果要垃圾回收,那么肯定是要用ParNew更好,因为多线程并行垃圾回收,充分利用多核CPU资源,可以提升性能。

如果你的Java程序是一个客户端程序,比如类似百度云网盘的Windows客户端这种运行在Windows个人操作系统上呢?

这种操作系统很多都是单核CPU,此时如果还是用ParNew来进行垃圾回收,就会导致一个CPU运行多个线程,反而加重了性能开销,可能效率还不如单线程好。

因为单CPU运行多线程会导致频繁的线上上下文切换,有效率开销。

所以如果是类似那种运行在Windows上的客户端程序,建议采用Serial垃圾回收器,单CPU单线程垃圾回收即可,反而效率更高。

一般很少有用Java写客户端程序,主要用来构建复杂的大规模后端业务系统,所以常见的是用 “-server” 指定为服务器模式,然后配合 ParNew 多线程垃圾回收器。

以上就是单线程和多线程对垃圾回收的使用场景。