关于CPU使用率飙升,我们需要了解什么?

21ic电子网 2020-06-11 00:00

1、CPU 使用率怎么计算?


CPU% = (1 - idleTime / sysTime) * 100

  • idleTime:CPU处于空闲状态的时间

  • sysTime:CPU处于用户态和内核台的时间总和


2、CPU 使用率跟啥有关系?


常听说计算密集型的程序是比较耗 CPU 使用率的。


3、CPU 与进程、线程有关系么?


现在分时操作系统是通过循轮方式分配时间片进行进程调度的,如果进程在等待或阻塞,不会造成 CPU 资源使用。线程称为轻进程,共享进程资源,关于线程的调度,CPU 对于线程也是分时调度。而在 Java 中,线程的调用由 JVM 负责,线程的调度一般有两种模式,分时调度和抢占式调度。



4、一个 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


5、频繁 Young GC 会不会引起 CPU 使用率飚升?


会的。


Young GC 本身是 JVM 进行垃圾回收的操作,会计算内存和调用寄存器,频繁 Young GC 一定是会占用 CPU。


之前有个一个案例,for 循环从数据库查询数据集合,二次封装新的数据集合,这时如果量比较大时,内存没有足够的空间存储,那么 JVM 就会 GC 回收那些不再使用的数据,因此量大的时候,就会收到 CPU 使用率报警。


6、线程数很高的应用,CPU 使用率一定高么?


不会。


通过 jstack 查看系统线程状态,查看整个线程数很多,但 Runable 和 Running 状态的线程不多,这时 CPU 使用率不一定会高。


之前有过一个案例,查看系统线程数 1000+,jstack 分析 900多个线程是 BLOCKED 和 WAITING 状态的,这种线程是不会占用 CPU 的。


如果线程数很高,其实大多数原因是死锁,大量线程处于 BLOCKED 和 WAITING 状态。


7、CPU 使用率高的应用,线程数一定高么?


不会。


同上,CPU 使用率高的关键因素还是计算密集型操作,一个线程如果有大量计算,也会造成 CPU 使用率高,也是现在为什么一个大数据脚本任务,要大规模集群共同运算才能运行的原因。


8、BLOCKED 状态的线程会不会引起 CPU 使用率飚升?


不一定。


CPU使用率的飙升,更多是因为上下文的切换或者runnable状态线程过多导致。Blocked状态,未必会引起CPU上升。


9、分时操作系统 CPU us高或者sy高是什么意思?


通过top命令,可以观察到CPU的us,sy值,示例如下:

  • us 用户空间占用CPU百分比,简单来说,us高是因为程序导致的,通过分析线程堆栈,可以很容易的定位到问题线程。


  • sy 内核空间占用CPU百分比,sy高的时候,如果是程序问题导致,基本是因为线程上下文切换造成的。

CPU飙升线程定位示例:

public class cpuTest {
public static void main(String args[]){
for(int i=0;i<10;i++){
new Thread(){
public void run(){
try{
Thread.sleep(100000);
}catch(Exception e){}
}
}.start();
}
Thread t=new Thread(){
public void run(){
int i=0;
while(true){
i=(i++)/100;
}
}
};
t.setName("Busiest Thread");
t.start();
}
}


步骤1: 执行top -c ,显示进程运行信息列表,键入P (大写p),进程按照CPU使用率排序,最耗CPU的进程PID为18207

步骤2:首先我们可以通过top -Hp <pid>来看这个进程里所有线程的cpu消耗情况

$ top -Hp 18207top - 19:11:43 up 573 days,  2:43,  2 users,  load average: 3.03, 3.03, 3.02Tasks:  44 total,   1 running,  43 sleeping,   0 stopped,   0 zombieCpu(s): 18.8%us,  0.0%sy,  0.0%ni, 81.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%stMem:  99191752k total, 98683576k used,   508176k free,   128248k buffersSwap:  1999864k total,   191064k used,  1808800k free, 17413760k cached PID  USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND18250 admin     20   0 26.1g  28m  10m R 99.9  0.0   0:19.50 java Test18207 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java Test18208 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.09 java Test18209 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java Test18210 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java Test18211 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java

cpu最高的线程是pid为18250的线程,占了99.9%

步骤3:printf “%x\n” 18250将线程PID转化为16进制

$ printf “%x\n” 18250

0X47A

...

步骤4:jstack 18207|grep'0X47A'-C5 --color找出进程中消耗CPU最多的线程栈

$ jstack 18207|grep'0X47A'-C5 --colorFull thread dump OpenJDK 64-Bit Server VM (25.66-b60 mixed mode):"Attach Listener" #30 daemon prio=9 os_prio=0 tid=0x00007fb90be13000 nid=0x47d7 waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"DestroyJavaVM" #29 prio=5 os_prio=0 tid=0x00007fb96245b800 nid=0x4720 waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"Busiest Thread" #28 prio=5 os_prio=0 tid=0x00007fb91498d000 nid=0x474a runnable [0x00007fb9065fe000]   java.lang.Thread.State: RUNNABLE    at Test$2.run(Test.java:18)"Thread-9" #27 prio=5 os_prio=0 tid=0x00007fb91498c800 nid=0x4749 waiting on condition [0x00007fb906bfe000]   java.lang.Thread.State: TIMED_WAITING (sleeping)    at java.lang.Thread.sleep(Native Method)    at Test$1.run(Test.java:9)...

因此,最耗cpu的线程是Busiest Thread


日常程序中常见的耗CPU的操作:

1、频繁GC,访问量高时,有可能造成频繁的GC、甚至FGC。当调用量大时,内存分配过快,就会造成GC线程不停的执行,导致CPU飙高

2、序列化与反序列化,后文中举了一个真实的案例,程序执行xml解析的时,调用量增大的情况下,导致了CPU被打满

3、加密解密

4、正则表达式校验,曾经线上发生一次血案,正则校验将CPU打满。大概原因是:Java 正则表达式使用的引擎实现是 NFA 自动机,这种引擎在进行字符匹配会发生回溯(backtracking)

5、线程上下文切换、当启动了很多线程,而这些线程都处于不断的阻塞状态(锁等待、IO等待等)和执行状态的变化过程中。当锁竞争激烈时,很容易出现这种情况

6、某些线程在做无阻塞的运算,简单的例子while(true)中不停的做运算,没有任何阻塞。写程序时,如果需要做很久的计算,可以适当将程序sleep下

7、Excel 导出事件


频繁GC案例

案例背景:网关服务进行控制单个url访问次数限流,CPU过若干天后飙升到80%,重启服务过若干天后又再次飙升到80%

分析过程:通过上述方法进行线程栈定位,并进行内存堆分析,发现pathRaterLimiterConcurrentHashMap对象占用大量堆空间,找到程序中对应的filter过滤器代码如下

public HttpRequestMessage apply(HttpRequestMessage request) {
String requestPath = request.getPath();
if (pathRaterLimiterConcurrentHashMap.containsKey(requestPath)) {
if (!pathRaterLimiterConcurrentHashMap.get(requestPath).tryAcquire()) {
log.warn("too many request:"+requestPath+",time:"+System.currentTimeMillis());
SessionContext context = request.getContext();
if(requestPath!=null && requestPath.equals("/voting/selection")){
context.setEndpoint(VoteTimeOutEndpoint.class.getCanonicalName());
}
//context.setEndpoint(ManyRequestsEndpoint.class.getCanonicalName());
request.setPath("/404.html");
context.setRouteVIP("limit-api");
}
} else {
pathRaterLimiterConcurrentHashMap.put(requestPath, RateLimiter.create(limit));
pathRaterLimiterConcurrentHashMap.get(requestPath).tryAcquire();
}
return request;
}

分析发现当url不断增加时,map的k-v会不断增加,以至于最后频繁触发fullgc,导致cpu飙升。

解决方案:跑一个定时任务线程定期清理map中的对象,后采用LRU算法重写一个maputil,定时清理过期的key值。


正则表达式案例

案例背景:前几天线上一个项目监控信息突然报告异常,上到机器上后查看相关资源的使用情况,发现 CPU 利用率将近 100%。

分析过程:

通过 Java 自带的线程 Dump 工具,我们导出了出问题的堆栈信息。我们可以看到所有的堆栈都指向了一个名为 validateUrl 的方法,这样的报错信息在堆栈中一共超过 100 处。通过排查代码,我们知道这个方法的主要功能是校验 URL 是否合法。

很奇怪,一个正则表达式怎么会导致 CPU 利用率居高不下。为了弄清楚复现问题,我们将其中的关键代码摘抄出来,做了个简单的单元测试。

public static void main(String[] args) {
String badRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)" +
"(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\\\/])+$";
String bugUrl = "http://www.fapiao.com/dddp-web/pdf/download?" +
"request=6e7JGxxxxx4ILd-kExxxxxxxqJ4-CHLmqVnenXC692m7" +
"4H38sdfdsazxcUmfcOH2fAfY1Vw__%5EDadIfJgiEf";
if (bugUrl.matches(badRegex)) {
System.out.println("match!!");
} else {
System.out.println("no match!!");
}
}

正则表达式分为三部分:

第一部分匹配 http 和 https 协议,第二部分匹配 www. 字符,第三部分匹配许多字符。我看着这个表达式发呆了许久,也没发现没有什么大的问题。

其实这里导致 CPU 使用率高的关键原因就是:Java 正则表达式使用的引擎实现是 NFA 自动机,这种正则表达式引擎在进行字符匹配时会发生回溯(backtracking)。而一旦发生回溯,那其消耗的时间就会变得很长,有可能是几分钟,也有可能是几个小时,时间长短取决于回溯的次数和复杂度。

正则表达式是一个很方便的匹配符号,但要实现这么复杂,功能如此强大的匹配语法,就必须要有一套算法来实现,而实现这套算法的东西就叫做正则表达式引擎。简单地说,实现正则表达式引擎的有两种方式:DFA 自动机(Deterministic Final Automata 确定型有穷自动机)和 NFA 自动机(Non deterministic Finite Automaton 不确定型有穷自动机)。

对于这两种自动机,他们有各自的区别,这里并不打算深入将它们的原理。简单地说,DFA 自动机的时间复杂度是线性的,更加稳定,但是功能有限。而 NFA 的时间复杂度比较不稳定,有时候很好,有时候不怎么好,好不好取决于你写的正则表达式。

解决方案:

其实在正则表达式中有这么三种模式:贪婪模式、懒惰模式、独占模式。在关于数量的匹配中,有 + ? * {min,max} 四种,如果只是单独使用,那么它们就是贪婪模式。

如果在他们之后加多一个 ? 符号,那么原先的贪婪模式就会变成懒惰模式,即尽可能少地匹配。但是懒惰模式还是会发生回溯现象的。

如果在他们之后加多一个 + 符号,那么原先的贪婪模式就会变成独占模式,即尽可能多地匹配,但是不回溯。

String goodRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)" +
"(([A-Za-z0-9-~]+).)++([A-Za-z0-9-~\\\\/])+$";


Excel导出案例

案例背景:京东某系统使用了poi-ooxml-3.5-final做excel导出功能。起初使用该版本的poi的HSSF配合多线程生成excel,没有任何问题,后来改成了XSSF生成后上线,导出3w条数据时,cpu使用率达到了100%,内存达到了100%

由于cpu使用率打爆,内存打爆,整个服务器处于拒绝服务状态,而呈现到前端则是应用系统大部分卡死。于是业务方不断反复点击导出按钮,状况不断扩大到集群内其他机器上,导致集群出现雪崩现象。

分析过程

由于服务器已经被打死,内存那么高,根本无法dump线上堆内存,甚至连jstack查看线程栈都无法使用。因此尝试在测试机复盘

可见eden空间的s0和s1已经无法交换了,eden空间已经完全打满,old空间也一样打满,yong gc和full gc都非常频繁,cpu自然使用率高了,不过不足以打满整个cpu!现在目前定位到了fullgc没有回收垃圾,那么需要找到内存打满和为啥没回收的原因。要想找到内存打满的原因肯定需要分析heap空间对象。

由于问题出现在导出报表,并且已知升级了版本并且改成了单线程导出就解决了,同时之前使用HSSF的时候并没有出现问题,也证明了业务代码没有问题,问题出现在XSSF的版本和多线程上。所以本地可以模拟poi-ooxml-3.5-FINAL的XSSF进行大量数据的导出实验,同时需要进行多线程导出。

在本地mock数据可以使用简单的大量对象构成的结构进行导出,线上30个列导出,本地测试5个列,线上是本地的6倍,线上的每一行的数据量必然要比本地的数据量大很多。同时怀疑是poi-ooxml-3.5-FINAL内存泄露或内存管理出现的问题,那么其实不需要4g内存,在2g的内存下压榨到死看看heap中大量的对象是不是poi相关的就可以了。然后再升级下版本,继续压榨一下看看会不会压死即可。

public static void main(String[] args) {
int size = 500000;
List<User> users = new ArrayList<>(size);
User user;
for (int i = 0; i < size; i++) {
user = new User();
user.setId(Integer.toUnsignedLong(i));
user.setAge(i + 10);
user.setName("user" + i);
user.setRemark(System.currentTimeMillis() + "");
user.setSex("男");
users.add(user);
}

new Thread(() -{
String[] columnName = {"用户id", "姓名", "年龄", "性别", "备注"};
Object[][] data = new Object[size][5];
int index = 0;
for (User u : users) {
data[index][0] = u.getId();
data[index][1] = u.getName();
data[index][2] = u.getAge();
data[index][3] = u.getSex();
data[index][4] = u.getRemark();
index++;
}
XSSFWorkbook xssfWorkbook = generateExcel("test", "test", columnName, data);
}).start();
try {
Thread.currentThread().join();//等待子线程结束
} catch (InterruptedException e) {
e.printStackTrace();
}
}


模拟现象与线上情况类似,大量cpu占用在XSSFCell.setCellValue中,生成excel generateExcel就占据了所有的cpu,堆信息全是POI对象

这里还需要注意的是,需要验证poi-ooxml-3.5-FINAL在多线程情况下是否会出现这个问题,验证很简单,把new Thread去掉,直接在主线程导出。这里直接说明实验结果,new Thread去了依然内存爆满!

解决方案

查看poi官网的change log http://poi.apache.org/changes.html ,既然3.5-FINAL的XSSF有问题,向上查找3.5-FINAL之后的XSSF相关字样的信息,会发现在3.6中memory usage optimization in xssf - avoid creating parentless xml beans,xxsf进行中做了内存优化 - 避免了创建无父类的xml bean对象


所以得出结论,升级poi-oxxml版本到3.6或者更高版本!


   
           
来源:技术让梦想更伟大
21ic电子网 即时传播最新电子科技信息,汇聚业界精英精彩视点。
评论
  • 耳机虽看似一个简单的设备,但不仅只是听音乐功能,它已经成为日常生活和专业领域中不可或缺的一部分。从个人娱乐到专业录音,再到公共和私人通讯,耳机的使用无处不在。使用高质量的耳机不仅可以提供优良的声音体验,还能在长时间使用中保护使用者听力健康。耳机产品的质量,除了验证产品是否符合法规标准,也能透过全面性的测试和认证过程,确保耳机在各方面:从音质到耐用性,再到用户舒适度,都能达到或超越行业标准。这不仅保护了消费者的投资,也提升了该公司在整个行业的产品质量和信誉!客户面临到的各种困难一家耳机制造商想要透
    百佳泰测试实验室 2024-12-20 10:37 138浏览
  • 随着工业自动化和智能化的发展,电机控制系统正向更高精度、更快响应和更高稳定性的方向发展。高速光耦作为一种电气隔离与信号传输的核心器件,在现代电机控制中扮演着至关重要的角色。本文将详细介绍高速光耦在电机控制中的应用优势及其在实际工控系统中的重要性。高速光耦的基本原理及优势高速光耦是一种光电耦合器件,通过光信号传递电信号,实现输入输出端的电气隔离。这种隔离可以有效保护电路免受高压、电流浪涌等干扰。相比传统的光耦,高速光耦具备更快的响应速度,通常可以达到几百纳秒到几微秒级别的传输延迟。电气隔离:高速光
    晶台光耦 2024-12-20 10:18 125浏览
  • 由于该文反应热烈,受到了众多工程师的关注,衷心感谢广大优秀工程师同仁的建言献策。特针对该技术点更新一版相关内容! 再次感谢大家的宝贵建议!填充铜(Solid Copper)和网格铜(Hatched Copper)是PCB设计中两种不同的铺铜方式,它们在电气性能、热管理、加工工艺和成本方面存在一些区别:1. 电气性能:填充铜:提供连续的导电层,具有极低的电阻和最小的电压降。适合大电流应用,并能提供优秀的电磁屏蔽效果,显著提高电磁兼容性。网格铜:由于铜线之间存在间隔,电阻相对较高,电压降也
    为昕科技 2024-12-18 17:11 135浏览
  •         在上文中,我们介绍了IEEE 802.3cz[1]协议提出背景,旨在定义一套光纤以太网在车载领域的应用标准,并介绍了XMII以及PCS子层的相关机制,在本篇中,将围绕IEEE 802.3cz-MultiGBASE-AU物理层的两个可选功能进行介绍。EEE功能        节能以太网(Energy-Efficient Ethernet)是用于在网络空闲时降低设备功耗的功能,在802.3cz的定义中,链
    经纬恒润 2024-12-19 18:47 79浏览
  • 汽车驾驶员监控系统又称DMS,是一种集中在车辆中的技术,用于实时跟踪和评估驾驶员状态及驾驶行为。随着汽车产业智能化转型,整合AI技术的DMS逐渐成为主流,AI模型通过大量数据进行持续训练,使得驾驶监控更加高效和精准。 驾驶员监测系统主要通过传感器、摄像头收集驾驶员的面部图像,定位头部姿势、人脸特征及行为特征,并通过各种异常驾驶行为检测模型运算来识别驾驶员的当前状态。如果出现任何异常驾驶行为(如疲劳,分心,抽烟,接打电话,无安全带等),将发出声音及视觉警报。此外,驾驶员的行为数据会被记录
    启扬ARM嵌入式 2024-12-20 09:14 84浏览
  • 沉寂已久的无人出租车赛道,在2024年突然升温了。前脚百度旗下萝卜快跑,宣布无人驾驶单量突破800万单;后脚特斯拉就于北京时间10月11日上午,召开了以“We,Robot”为主题的发布会,公布了无人驾驶车型Cybercab和Robovan,就连低调了好几个月的滴滴也在悄悄扩编,大手笔加码Robotaxi。不止是滴滴、百度、特斯拉,作为Robotaxi的重磅选手,文远知行与小马智行,也分别在10月份先后启动美股IPO,极氪也在近日宣布,其与Waymo合作开发的无人驾驶出行汽车将大规模量产交付,无人
    刘旷 2024-12-19 11:39 140浏览
  • //```c #include "..\..\comm\AI8051U.h"  // 包含头文件,定义了硬件寄存器和常量 #include "stdio.h"              // 标准输入输出库 #include "intrins.h"         &n
    丙丁先生 2024-12-20 10:18 79浏览
  • By Toradex秦海1). 简介为了保证基于 IEEE 802.3 协议设计的以太网设备接口可以互相兼容互联互通,需要进行 Ethernet Compliance 一致性测试,相关的技术原理说明请参考如下文章,本文就不赘述,主要展示基于 NXP i.MX8M Mini ARM 处理器平台进行 1000M/100M/10M 以太网端口进行一致性测试的测试流程。https://www.toradex.com
    hai.qin_651820742 2024-12-19 15:20 140浏览
  • 百佳泰特为您整理2024年12月各大Logo的最新规格信息。——————————USB▶ 百佳泰获授权进行 USB Active Cable 认证。▶ 所有符合 USB PD 3.2 标准的产品都有资格获得USB-IF 认证——————————Bluetooth®▶ Remote UPF Testing针对所有低功耗音频(LE Audio)和网格(Mesh)规范的远程互操作性测试已开放,蓝牙会员可使用该测试,这是随时测试产品的又一绝佳途径。——————————PCI Express▶ 2025年
    百佳泰测试实验室 2024-12-20 10:33 99浏览
  •         不卖关子先说感受,真本书真是相见恨晚啊。字面意思,见到太晚了,我刚毕业或者刚做电子行业就应该接触到这本书的。我自己跌跌撞撞那么多年走了多少弯路,掉过多少坑,都是血泪史啊,要是提前能看到这本书很多弯路很多坑都是可以避免的,可惜这本书是今年出的,羡慕现在的年轻人能有这么丰富完善的资料可以学习,想当年我纯靠百度和论坛搜索、求助啊,连个正经师傅都没有,从软件安装到一步一布操作纯靠自己瞎摸索,然后就是搜索各种教程视频,说出来都是泪啊。  &
    DrouSherry 2024-12-19 20:00 87浏览
  • ​本文介绍PC电脑端运行VMware环境下,同时烧录固件检测不到设备的解决方法。触觉智能Purple Pi OH鸿蒙开发板演示,搭载了瑞芯微RK3566芯片,类树莓派设计,Laval官方社区主荐,已适配全新OpenHarmony5.0 Release系统!PC端烧录固件时提示没有发现设备按照各型号烧录手册中进入loader模式的操作方法,让开发板连接到PC端。正常来说开发板烧录时会显示“发现一个LOADER设备”,异常情况下,会提示“没有发现设备”,如下图所示: 解决步骤当在烧录系统固
    Industio_触觉智能 2024-12-18 18:07 79浏览
  • 在强调可移植性(portable)的年代,人称「二合一笔电」的平板笔电便成为许多消费者趋之若鹜的3C产品。说到平板笔电,不论是其双向连接设计,面板与键盘底座可分离的独特功能,再加上兼具笔电模式、平板模式、翻转模式及帐篷模式等多种使用方式,让使用者在不同的使用情境下都能随意调整,轻巧灵活的便利性也为多数消费者提供了绝佳的使用体验。然而也正是这样的独特设计,潜藏着传统笔电供货商在产品设计上容易忽视的潜在风险。平板笔电Surface Pro 7+ 的各种使用模式。图片出处:Microsoft Comm
    百佳泰测试实验室 2024-12-19 17:40 164浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦