维护公司的一个项目, 运行在jvm 上的scala 语言编写; Akka Actor System 实现的一个web 系统。
问题: 项目启动后就能占用50% cpu 资源, 8核cpu的情况下, 由于刚启动没有任何负载, 占用cpu明显过多。
cpu 占用过多可能的几种情况:
- 一直在GC , gc overhead exceed limit
- 死循环,占用线程不释放
- 线程过多, 线程切换上下文开销大
由于项目刚启动就占用大cpu ,怀疑是项目中的定时任务初始化不当,将定时任务代码注销, 启动后cpu 占用没变,排除定时任务问题
通过jdk自带的分析工具,进行分析, 一般情况下我们都设置了环境变量,可以在命令行下直接使用, jdk自带了很多分析工具,在对应安装目录的bin路径下,可以自行搜索其用法。又由于该项目运行在jvm上,jvm具有跨平台的熟悉,所以直接在window下进行分析。Linux 下没有图形化界面,需要些额外设置。
打开cmd, 输入:jvisualvm
如图所示:左上角有可以分析的运行在jvm上的进程。可以看到也可以远程分析,需要额外的设置,对于我们这个问题,可以本地分析。

启动程序,重新开一个cmd, 我本地项目通过 java -jar xxx.war 启动,然后就可以在分析界面看到对应的xxx.war进程。如图所示

双击打开,可以看到,好多分析项, 有gc情况,cpu情况,线程数情况。

线程数接近500, 刚启动线程数接近500,线程数过高,可以向下翻动,发现很多线程都是在休眠状态,并没有得到执行。 同时可以检测没有死锁发生,不会线程占用cpu不释放。在到gc 面板看下gc频率。

通过上图分析,gc 频率正常。
综上,怀疑是项目初始化不当,导致线程数过多, 检查代码,发现项目初始化时,容器初始化过多, 一个容器初始化会有很多的守护线程,导致线程数过多,cpu占用过多。
项目使用的是akka actor system. 在项目中初始化了ActorSystem多次, 查阅资料,发现akka官网有对actorsystem 的说明:

多实例化的ActorSystem 也只实例化一次,重新编译,运行,发现线程数降下来了,cpu也降下来了。
本文讲述了在JVM上运行的Scala项目遇到CPU占用过高问题的排查过程。通过jvisualvm工具,发现项目启动时线程数接近500,且多数线程处于休眠状态。进一步分析排除了定时任务和GC问题。最终定位为Akka ActorSystem初始化导致的线程过多,调整代码后降低线程数,成功解决了CPU占用过高的问题。

被折叠的 条评论
为什么被折叠?



