java如何将线程与cpu的核绑定_JVM(13)年轻代垃圾回收器ParNew是如何工作的?

喜欢文章的可以关注下公众号!谢谢支持!!

66c05cff78d7f92cb2b8030d50c26165.png


    之前的文章已经把整个JVM的核心运行原理梳理清楚了:

    【1】对象在新生代分配,什么时候会触发Minor GC。   

    【2】触发Minor GC之前会如何检查老年代可用内存大小和新生代对象大小,如何检查老年代可用内存大小和历次Minor GC之后升入老年代的平均对象大小。
    【3】什么情况下Minor GC之前会提前触发Full GC,什么情况下会直接触发Minor GC。
    【4】Minor GC之后有哪几种情况对象会进入老年代。

    也大概知道了垃圾回收器、垃圾回收线程、垃圾回收算法之间的关系,包括垃圾回收的过程中的“Stop the World”现象和场景对系统运行性能的影响。

    =>JVM(8)对象触发回收的条件

    =>JVM(9)JVM的垃圾回收算法,以及优劣

    =>JVM(10)年轻代和老年代适合的算法

    =>JVM(11)记录一次JVM的问题与优化思路

    =>JVM(12)让人无奈的"Stop the world"

    接下去的文章我们就要对常见的新生代和老年代的垃圾回收器的运行原理进行了解,以及常见的垃圾回收参数一般的设置方式。

    新生代垃圾回收器:ParNew

    一般来说,在之前没有最新的G1垃圾回收器的话,线上系统都是ParNew垃圾回收器作为新生代的垃圾回收器。现在即使有了G1,其实很多线上系统还是用的ParNew。
    通常运行在服务器上的Java系统,都可以充分利用服务器的多核CPU的优势,假设你的服务器是4核CPU,如果对新生代垃圾回收的时候,仅仅使用单线程进行垃圾回收,是不是会导致没法充分利用CPU资源?

c6afeca820c0d8397a78fc46e08a6389.png

    如上图,在垃圾回收的时候,都把系统程序所有的工作线程全部停掉了,就一个垃圾回收线程在运行,那么此时4核CPU的资源根本没法充分利用,理论上4核CPU就可以支持4个垃圾回收线程并行执行,可以提升4倍的性能!
    所以说,新生代的ParNew垃圾回收器就是多线程垃圾回收机制,另外一种Serial垃圾回收器是单线程垃圾回收,他们俩都是回收新生代的,唯一的区别就是单线程和多线程的区别,但是垃圾回收算法是完全一样的。
    看下图,ParNew垃圾回收器如果一旦在合适的时机执行Minor GC的时候,就会把系统程序的工作线程全部停掉,禁止程序继续运行创建新的对象,然后自己就用多个垃圾回收线程去进行垃圾回收,回收的机制和算法就跟之前文章介绍的是一样的。

cab62d8e62eee5452a5d1ce67bbd7242.png

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


    一般来说,对于系统部署启动的时候,我们有多种方式来设置JVM参数了,在IntelliJ IDEA中可以设置Debug JVM Arguments,使用“java -jar”命令启动时直接在后面跟上JVM参数即可。部署到Tomcat时可以在Tomcat的catalina.sh中设置Tomcat的JVM参数,使用Spring Boot也可以在启动时指定JVM参数。

    在启动系统的时候如果要指定使用ParNew垃圾回收器,是用什么参数呢? 

    很简单,使用“-XX:+UseParNewGC”选项,JVM启动之后对新生代进行垃圾回收的,就是ParNew垃圾回收器了。那么Minor GC的时机,检查机制,包括垃圾回收的具体过程,以及对象升入老年代的机制,都是我们之前介绍的那套原理,只需要知道,ParNew会使用多个线程来进行垃圾回收。

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

    因为现在一般我们系统的服务器都是多核CPU的,所以为了在垃圾回收的时候充分利用多核CPU的资源,一旦我们指定了使用ParNew垃圾回收器之后,默认给自己设置的垃圾回收线程的数量就是跟CPU的核数是一样的。
    比如我们线上机器假设用的是4核CPU,或者8核CPU,或者16核CPU,那么此时ParNew的垃圾回收线程数就会分别是4个线程、8个线程、16个线程,这一般不用我们手动去调节,因为跟CPU核数一样的线程数量,是可以充分进行并行处理的。
    比如下图,每个线程都通过一个CPU在运行:

c2a137c2c985c1aec730f02bfb8f7fb2.png


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

    所以可以一起思考一个问题,到底是用单线程垃圾回收好,还是多线程垃圾回收好?到底是Serial垃圾回收器好还是ParNew垃圾回收器好?

    启动系统的时候是可以区分服务器模式和客户端模式的,如果你启动系统的时候加入“-server”就是服务器模式,如果加入“-cilent”就是客户端模式。他们俩的区别就是,如果你的系统部署在比如4核8G的Linux服务器上,那么就应该用服务器模式,如果你的系统是运行在比如Windows上的客户端程序,那么就应该是客户端模式。

    那么服务器模式和客户端模式的区别是什么呢?
    服务器模式通常运行我们的网站系统、电商系统、业务系统、APP后台系统之类的大型系统,一般都是多核CPU,所以此时如果要垃圾回收,那么肯定是用ParNew更好,因为多线程并行垃圾回收,充分利用多核CPU资源,可以提升性能。如下图。

9a38b266f590b0ee5ea7f17a36701809.png

    如果你部署在服务器上,但是你用了单线程垃圾回收,那么就有一些CPU是被浪费了,根本没用上。比如下图:

980bfba0ffe33a200cafbe813b9b3d1f.png

    那么如果Java程序是一个客户端程序,比如类似百度云网盘的Windows客户端,或者是有道云笔记的Windows客户端。这种操作系统很多都是单核CPU,此时你如果要是还是用ParNew来进行垃圾回收,就会导致一个CPU运行多个线程,反而加重了性能开销,可能效率还不如单线程好,因为单CPU运行多线程会导致频繁的线上上下文切换,有效率开销,如下图:

0fd4f04f44a9b681aee3387ccd2f8ce2.png


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

ba828e366bbfa503df2da83f2c8f026c.png

    现在一般很少有用Java写客户端程序的,几乎很少见,Java现在主要是用来构建复杂的大规模后端业务系统的,所以常见的还是用“-server”指定为服务器模式,然后配合ParNew多线程垃圾回收器。
    但还是建议应该清楚单线程和多线程对垃圾回收的适用场景。

     如果大家对这块有更好的见解以及问题,或者本文有书写错误的地方,也可以进行评论交流。点点关注哦!!!谢谢支持!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值