王洪涛
京东商城,商家研发部架构师。丰富的构建高性能高可用大规模分布式系统的研发、架构经验。2015年加入京东,目前负责服务市场的系统研发工作。
我的疑惑
一个 while 死循环,会不会引起 CPU 使用率飚升?
频繁 Young GC 会不会引起 CPU 使用率飚升?
线程数很高的应用,CPU 使用率一定高么?
CPU 使用率高的应用,线程数一定高么?
BLOCKED 状态的线程会不会引起 CPU 使用率飚升?
分时操作系统 CPU 是耗费 us ? 还是耗费 sy ?
我的思考
CPU 使用率怎么算?
CPU% = 1 - idleTime / sysTime * 100
idleTime:CPU处于空闲状态的时间
sysTime:CPU处于用户态和内核台的时间总和
CPU 使用率跟啥有关系?
我们常听说计算密集型的程序是比较耗 CPU 使用率的。
那 JAVA 应用中哪些操作是比较耗 CPU 使用的?
列举下日常程序中常见的耗CPU的操作:
频繁GC,访问量高时,有可能造成频繁的GC、甚至FGC。当调用量大时,内存分配过快,就会造成GC线程不停的执行,导致CPU飙高。
序列化与反序列化,后文中举了一个真实的案例,程序执行xml解析的时,调用量增大的情况下,导致了CPU被打满。
加密、解密。
正则表达式校验,曾经线上发生一次血案,正则校验将CPU打满。大概原因是:Java 正则表达式使用的引擎实现是 NFA 自动机,这种引擎在进行字符匹配会发生回溯(backtracking)。
线程上下文切换、当启动了很多线程,而这些线程都处于不断的阻塞状态(锁等待、IO等待等)和执行状态的变化过程中。当锁竞争激烈时,很容易出现这种情况。
某些线程在做无阻塞的运算,简单的例子while(true)中不停的做运算,没有任何阻塞。写程序时,如果需要做很久的计算,可以适当将程序sleep下。
CPU 与进程、线程有关系么?
现在分时操作系统是通过循轮方式分配时间片进行进程调度的,如果进程在等待或阻塞,不会造成 CPU 资源使用。线程称为轻进程,共享进程资源,关于线程的调度,CPU 对于线程也是分时调度。而在 Java 中,线程的调用由 JVM 负责,线程的调度一般有两种模式,分时调度和抢占式调度。
我的解惑
一个 while 死循环,会不会引起 CPU 使用率飚升?
会的。先不说别的,死循环会调用 CPU 寄存器进行计数,这个操作就会占用 CPU。其次,如果线程一直处于死循环状态,CPU 调用会进行线程切换么?
死循环不会让出 CPU,除非操作系统时间片到期,但死循环会不断向系统申请时间片,直到系统没有空闲时间做别的事情。
这个问题在 stackoverflow 也有人提问:why does an infinite loop of the unintended kind increase the CPU use?
地址:https://stackoverflow.com/questions/2846165/why-does-an-infinite-loop-of-the-unintended-kind-increase-the-cpu-use
频繁 Young GC 会不会引起 CPU 使用率飚升?
会的。Young GC 本身是 JVM 进行垃圾回收的操作,会计算内存和调用寄存器,频繁 Young GC 一定是会占用 CPU。
之前有个一个案例,for 循环从数据库查询数据集合,二次封装新的数据集合,这时如果量比较大时,内存没有足够的空间存储,那么 JVM 就会 GC 回收那些不再使用的数据,因此量大的时候,就会收到 CPU 使用率报警。
线程数很高的应用,CPU 使用率一定高么?
不会。通过 jstack 查看系统线程状态,查看整个线程数很多,但 Runable 和 Running 状态的线程不多,这时 CPU 使用率不一定会高。
之前有过一个案例,查看系统线程数 1000+,jstack 分析 900多个线程是 BLOCKED 和 WAITING 状态的,这种线程是不会占用 CPU 的。
如果线程数很高,其实大多数原因是死锁,大量线程处于 BLOCKED 和 WAITING 状态。
CPU 使用率高的应用,线程数一定高么?
不会。同上,CPU 使用率高的关键因素还是计算密集型操作,一个线程如果有大量计算,也会造成 CPU 使用率高,也是现在为什么一个大数据脚本任务,要大规模集群共同运算才能运行的原因。
BLOCKED 状态的线程会不会引起 CPU 使用率飚升?
不一定,CPU使用率的飙升,更多是因为上下文的切换或者runnable状态线程过多导致。Blocked状态,未必会引起CPU上升。
分时操作系统 CPU us高或者sy高是什么意思?
通过top命令,我们可以观察到cpu的us,sy值,示例如下:
Us 用户空间占用CPU百分比,简单来说,us高是因为我们的程序导致的,通过分析线程堆栈,可以很容易的定位到问题线程。
Sy 内核空间占用CPU百分比,sy高的时候,如果是程序问题导致,基本是因为线程上下文切换造成的。
我的经验
平时怎么定位 CPU 使用率高的原因的?
其实网上有个教程和方法,我简述我的分析过程。
首先发现某台应用 CPU 使用率高,一要看先线程数、JVM、系统 load 等参数,共同作证。二要打印 jstack,通过工具分析线程情况,推荐 fastThread 这个在线的 Thread 分析工具。
以下是线上发生的真实案例,简要介绍下:
某日晚,突然收到短信报警,CPU利用率100%。立刻dump该机器jstack,通过 http://fastthread.io/ 查看日志如下:
进一步查看具体日志:
通过这段日志,已经定位到了具体CPU被打满的方法,接收MQ之后,MQ消息体为xml,反序列化的时候,造成了CPU飙高。
希望本文对大家有所帮助。