欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

解决JVM的CPU使用率高

程序员文章站 2022-04-13 09:29:28
...

问题:每天的系统自动计算都会报CPU使用率过高短信报警与邮件报警

最终问题定位:vendor信息同步redis中代码 for循环中使用list.contains()线性查找判断sku是否存在,该代码块的时间复杂度近似O(n*m)导致线程并发情况下CPU耗用高

解决方案:把list数据放入HashSet判断sku是否存在,把CPU使用率从90+%降到了10+%及以下

通常的解决思路是:

  1. top命令找出有问题Java进程及其线程号:
    1. 开启线程显示模式
    2. CPU使用率排序
    3. 记下Java进程号及其CPU高的线程号
  2. 手动转成十六进制(可以用printf %x 1234)。
  3. jstack有问题的Java进程。
  4. grep十六进制的线程id,找到线程栈,查看关联的问题代码块。

     参见:https://github.com/oldratlee/useful-scripts/blob/master/docs/java.md#beer-show-busy-java-threadssh

本次解决时,基本知道哪个代码模块Job有问题,同时无法访问线上系统环境(可以申请),所以省略了大部分步骤,只使用了的jstack来解决问题。

本次解决思路:

1、根据报警时间与当时正在跑的Job,定位到具体JOB,当时只有VENDOR一个Job在跑

解决JVM的CPU使用率高
            
    
    博客分类: JVM JVMCPU 

解决JVM的CPU使用率高
            
    
    博客分类: JVM JVMCPU 

2、晚上跑vendor信息同步redis,在cpu使用率高时,选择一台机器,执行 jstack -l  pid命令,并导出栈信息

3、查看栈信息,找到具体的线程栈,查看当时栈都在执行什么操作,发现vendor的10个线程所有Thread栈都在执行com.calc.redis.adaptor.VendorSKURedisAdaptor.getValue(VendorSKURedisAdaptor.java:66)

解决JVM的CPU使用率高
            
    
    博客分类: JVM JVMCPU 

4、分析具体的代码,基本定位到使用list.contains()线性查找导致CPU使用过高

解决JVM的CPU使用率高
            
    
    博客分类: JVM JVMCPU 

5、将上段代码由list改为HashSet,上线测试,CPU使用率正常,问题解决。如果CPU还高的话就需要循环以上步骤,改进耗CPU的代码

 

Tips:解决问题过程中发现的一个有关线程池的未合理使用场景

定位到具体job,分析相应时间段的任务队列表时,发现CPU高集中报在Job会连续占用多个id相连的任务阶段。线程池固定大小是10,队列固定也是10,RejectedExecutionHandler策略使用的是CallerRunsPolicy,当CallerRunsPolicy生效跑的过程中,线程池不会放入新的任务,使得CallerRunsPolicy执行完后线程池队列基本是空的,未能充分使用线程资源。

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 120, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.CallerRunsPolicy());

这时需要考虑如何合理的使用线程资源,诸位自己想想吧。

相关标签: JVM CPU