linux杀掉cpu使用率高的进程,线上linux系统故障排查之一:CPU使用率过高_朱太帅的博客-程序员宅基地

技术标签: linux杀掉cpu使用率高的进程  

一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环。

下面我们将一步步定位问题,详尽的介绍每一步骤的相关知识。

一、通过top命令定位占用cpu高的进程

执行top命令得到以下结果:

6d573e42310a

top命令执行结果

通过上图可以明显看出进程PID41843占用cpu过高,明显存在问题,定位到了进程id。当然如果你想只观察进程PID41843的CPU和内存以及负载情况,可以使用以下命令

top -p 41843。

结果如下:

6d573e42310a

top -p 41843命令执行结果

这里顺便解释下上图各个参数的意义,有利于读者更好的排查问题。

第一行是任务队列信息

top - 14:06:34 up 537 days, 6 min, 6 users, load average: 0.41, 0.45, 0.43

任务队列信息

含义

14:06:34

当前时间

537 days

系统运行时间

6 min

用户在线时间

6 users

在线用户数

load average: 0.41, 0.45, 0.43

系统负载,即任务队列的平均长度。1分钟前、5分钟前、15分钟前平均负载

2)第二行为进程的信息

进程信息

含义

Tasks: 1 total

进程总数

0 running

正在运行的进程数

1 sleeping

睡眠的进程数

0 stopped

停止的进程数

0 zombie

僵尸进程数

第三行为cpu信息

cpu信息

含义

6.1% us

用户空间占用CPU百分比

1.5% sy

内核空间占用CPU百分比

0.0% ni

用户进程空间内改变过优先级的进程占用CPU百分比

92.2% id

空闲CPU百分比

0.0% wa

等待输入输出的CPU时间百分比

0.0% hi

硬件中断

0.0% si

软件中断

0.0%st

实时

第四、五行为内存信息。

内容如下:

物理内存信息

含义

Mem: 191272k total

物理内存总量

173656k used

使用的物理内存总量

17616k free

空闲内存总量

22052k buffers

用作内核缓存的内存量

交换区信息

含义

Swap: 192772k total

交换区总量

0k used

使用的交换区总量

192772k free

空闲交换区总量

123988k cached

缓冲的交换区总量

二、通过top命令定位问题进程中每个线程占用cpu情况

通过问题进程中每个线程占用cpu情况使用可以使用如下命令:

top -p 41843 -H

查看进程PID41843的每一个线程占用CPU情况,如图。

6d573e42310a

top -p 41843 -H的执行结果

由上图明显可以发现,线程PID41892CPU占用率最高,接下来定位该线程的代码是否出现异常导致cpu占用过高。

三、通过jstack 命令定位问题代码

上一步发现PID41892占用的CPU过高,就将这个PID转换成16进制,易知,PID41892转化成16进制为a3a4。使用如下命令命令定位问题代码:

jstack 41892 | grep a3a4

输出如下:

"Thread" prio=10 tid=0x00007f950043e000 nid=0x54ee in test();

可以分析得到: 线程Thread下的wait()函数cpu使用率很高,查看源代码中的test()函数代码如下:

public void test(){

while(true){

for(int i = 0 ;i<100;i++);

}

}

while循环无法结束,一直抢占cpu,导致程序cpu使用过高,修改代码即可。

到此为止,因为代码问题导致的cpu使用过高的故障排查方法就介绍完了。

tips:由于内存的原因,频繁的GC,也可能导致cpu使用过高,内存的解决方案在文章《线上linux系统故障排查之二:内存占用过高》中介绍。

四、终极大杀器

笔者是喜欢一、二、三步骤定位cpu使用率过高的问题,但是如果读者觉得以上方法不喜欢或者以上无法定位问题时,可以使用jstack方法获取进程PID41843包含的运行线程的所有状态。使用如下命令:

jstack -l 41843

或者将结果输入在dump.txt文档中:jstack -l 41843 >> dump.txt

首先我们来介绍下,Jstack的输出中,Java线程状态的四种状态的概念:

RUNNABLE 线程运行中或I/O等待

BLOCKED 线程在等待monitor锁(synchronized关键字)

TIMED_WAITING 线程在等待唤醒,但设置了时限

WAITING 线程在无限等待唤醒

接下来用简单的代码模拟这4种状态的发生,同时介绍下问题的排查方法。

1) 让线程一直处于RUNNABLE状态

public static void main(String[] args) {

printPId();//打印进程id

runnable();//模拟RUNNABLE状态方法,第14行

}

public static void runnable(){//第19行

int i = 0;

while (true) {

i++;

}

}

public static void printPId() {

String name = ManagementFactory.getRuntimeMXBean().getName();

System.out.println(name.split("@")[0]);

}

执行main函数,使用命令jstack -l PID(pid为printPId函数打印的值),得到以下输出信息:状态为RUNNABLE,程序在Test类的runnable()方法中占用cpu,一般该状态不会出现问题。但是如果多次执行该命令,发现cpu在持续执行该方法,且cpu使用过高,可以排查runnable()方法是否存在死循环等持续占用cpu的情况。

"main" #1 prio=5 os_prio=0 tid=0x00000000023fe000 nid=0x2ab8 runnable [0x0000000

0026df000]

java.lang.Thread.State: RUNNABLE

at Test.runnable(Test.java:19)

at Test.main(Test.java:14)

Locked ownable synchronizers:

-None

2) 让线程一直处于BLOCKED状态(重点关注)

public static void main(String[] args) {

printPId();//打印进程id

blocked();//模拟BLOCKED状态方法,第16行

}

public static void blocked(){

Integer lock = 0;

new Thread() {

public void run() {

synchronized (lock) {

try {

Thread.sleep(1000 * 1000);//26行

} catch (Exception e) {

e.printStackTrace();

}

}

}

}.start();

try { Thread.sleep(100); } catch (Exception e) {e.printStackTrace();}

synchronized (lock) {

try {

Thread.sleep(10 * 1000);//第37行

} catch (Exception e) {

e.printStackTrace();

}

}

}

public static void printPId() {

String name = ManagementFactory.getRuntimeMXBean().getName();

System.out.println(name.split("@")[0]);

}

主线程sleep,先让另外一个线程拿到lock,并长期持有lock(sleep会持有锁,wait不会)。此时主线程会BLOCK住等待lock被释放,此时jstack的输出可以看到main线程状态是BLOCKED。

根据以下输出可以看出:

1)线程状态是 Blocked,阻塞状态。说明线程等待资源超时!

2)“ waiting to lock <0x00000000d6f7a970>”,指该地址被占用了,线程在等待给这个 0x00000000d6f7a970地址上锁。

3)在 dump 日志里查找字符串 0x00000000d6f7a970,如果发现有大量线程都在等待给这个地址上锁。则存在问题。继续查找字符串0x00000000d6f7a970,发现locked <0x00000000d6f7a970> (a java.lang.Integer)给地址上锁,却未释放,查找该出代码问题。

4)“waiting for monitor entry”说明此线程通过 synchronized(obj) {……} 申请进入了临界区。

5)第一行里,"main"是 Thread Name 。tid指Java Thread id。nid指native线程的id。prio是线程优先级。[0x00000000027af000]是线程栈起始地址。

"main" #1 prio=5 os_prio=0 tid=0x000000000244e000 nid=0x2218 waiting for monitor

entry [0x00000000027af000]

java.lang.Thread.State: BLOCKED (on object monitor)

at Test.blocked(Test.java:37)

-waiting to lock <0x00000000d6f7a970> (a java.lang.Integer)

at Test.main(Test.java:16)

Locked ownable synchronizers:

-None

"Thread-0" #10 prio=5 os_prio=0 tid=0x0000000058893800 nid=0x1cc8 waiting on con

dition [0x00000000599ae000]

java.lang.Thread.State: TIMED_WAITING (sleeping)

at java.lang.Thread.sleep(Native Method)

at Test$1.run(Test.java:26)

-locked <0x00000000d6f7a970> (a java.lang.Integer)

Locked ownable synchronizers:

-None

3) 让线程处于TIMED_WAITING状态

public static void main(String[] args) {

printPId();//打印进程id

timedWaiting();//模拟TIMED_WAITING状态方法

}

public static void timedWaiting() {

Integer lock = 0;

synchronized (lock) {

try {

lock.wait(100 * 1000);

} catch (Exception e) {

e.printStackTrace();

}

}

}

public static void printPId() {

String name = ManagementFactory.getRuntimeMXBean().getName();

System.out.println(name.split("@")[0]);

}

根据以下输出可以看出:

1)“TIMED_WAITING ”中的 timed_waiting 指等待状态,但这里指定了时间,到达指定的时间后自动退出等待状态。

"main" #1 prio=5 os_prio=0 tid=0x0000000001c1e000 nid=0x1c78 in Object.wait() [0

x000000000272f000]

java.lang.Thread.State: TIMED_WAITING (on object monitor)

at java.lang.Object.wait(Native Method)

-waiting on <0x00000000d6f7a970> (a java.lang.Integer)

at Test.timedWaiting(Test.java:25)

-locked <0x00000000d6f7a970> (a java.lang.Integer)

at Test.main(Test.java:18)

Locked ownable synchronizers:

-None

4) 让线程处于WAITING状态状态

public static void main(String[] args) {

printPId();//打印进程id

waiting();//模拟waiting状态方法

}

public static void waiting() {

Integer lock = 0;

synchronized (lock) {

try {

lock.wait();

} catch (Exception e) {

e.printStackTrace();

}

}

}

public static void printPId() {

String name = ManagementFactory.getRuntimeMXBean().getName();

System.out.println(name.split("@")[0]);

}

无超时的等待,必须等待lock.notify()或lock.notifyAll()或接收到interrupt信号才能退出等待状态。同理,ReentrantLock.lock()的无参方法调用,也会使线程状态变成WAITING。

"main" #1 prio=5 os_prio=0 tid=0x00000000024ce000 nid=0x2b14 in Object.wait() [0

x00000000025ef000]

java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)

-waiting on <0x00000000d6f7a970> (a java.lang.Integer)

at java.lang.Object.wait(Unknown Source)

at Test.waiting(Test.java:27)

-locked <0x00000000d6f7a970> (a java.lang.Integer)

at Test.main(Test.java:20)

Locked ownable synchronizers:

-None

掌握各个线程的状态和信息,将无往而不利~~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_29786123/article/details/116550540

智能推荐

oracle ebs 中om,Oracle EBS OM 保留订单_指南针丶的博客-程序员宅基地

DECLAREl_header_rec OE_ORDER_PUB.Header_Rec_Type;l_line_tbl OE_ORDER_PUB.Line_Tbl_Type;l_action_request_tbl OE_ORDER_PUB.Request_Tbl_Type;l_header_adj_tbl OE_ORDER_PUB.Header_Adj_Tbl_Type;l_line_adj_t...

mysql n叉树_MySQL为什么要使用B+树索引_王慧02012的博客-程序员宅基地

目录MySQL的存储结构表存储结构B+树索引结构B+树页节点结构B+树的检索过程为什么要用B+树索引二叉树多叉树B树B+树搞懂这个问题之前,我们首先来看一下MySQL表的存储结构,再分别对比二叉树、多叉树、B树和B+树的区别就都懂了。MySQL的存储结构表存储结构单位:表&gt;段&gt;区&gt;页&gt;行在数据库中, 不论读一行,还是读多行,都是将这些行所在的页进行加载。也就是说存储空间的基...

[GRE] 阅读超超高频逻辑单题 错题_He-lium_的博客-程序员宅基地

A law has been proposed requiring the cargo boxes of trucks carrying gravel to be covered by a tarpaulin, because vehicles driving close behind open-topped gravel trucks can be damaged by gravel flying off these trucks. The law is unlikely to substantiall.

Grep整理_q897130651的博客-程序员宅基地

Grep 用法准备test文件,内容如下:dlf testdlfthinkwww.baidu.comTEST 123Dlf's lemongrep Grepabcabc123abc123dlf123[www.baidu.com]1)grep -i "test" test.txt 搜索出含有“test” 字符串(-i:不区分大小)2)grep -i -n "test" test.txt 搜索出...

suse 查看java版本_SLES 11 中JDK的安装和配置_weixin_39614109的博客-程序员宅基地

1. 下载合适的JDK版本本人是在虚拟机中创建的SLES 11 SP1 X86_64的OS,所以下载的是对应的Linux x86_64版本,下载文件名为:jdk-7-linux-x64.rpm。Oracle提供了tar.gz和rpm两种下载格式,建议下载rpm格式,方便安装。下载路径为:http://download.oracle.com/otn-pub/Java/jdk/7/jdk-7-linu...

监听事件_雪夜如画的博客-程序员宅基地

开发工具与关键技术: VS, 监听作者:卢惠圳撰写时间:2019年6月16日有时会要在一个页面上显示2个表但是又不是同时显示,而是一个表先显示另一个表则是通过点击第一个表的某条数据在去显示而且点击不同数据出来的第二张表的数据也不一样,这样就需要用到监听事件,当然首先先将2个表的样式写好方便存放数据,代码如下图:然后就可以开始写监听事件了,当点击表格中的其中一行数据时就为当前点击的tr添加...

随便推点

spark while_Spark程序启动的几种姿势_weixin_39849070的博客-程序员宅基地

本文主要讲述了Spark启动的几种姿势。对于spark(streaming)程序,我们通常是用shell脚本进行启动,而脚本的调用通常是由crontab或者调度系统例如azkaban定时启动,当然azkaban还有创建依赖等等功能。如果我们的程序触发条件是由某个主动行为,而非固定时间点或者是依赖某个任务呢?比如我想调个接口就可以启动spark程序? 姿势一 Azkaban API 调用Azkaba...

lmdb.Error:“路径“+:���̿ռ䲻�㡣_GZKPeng的博客-程序员宅基地

一开始因为报的异常带乱码,所以以为是编码格式的问题,后来发现并不是,查看报异常位置:env = lmdb.open(outputPath, map_size=1099511627776)第一个参数是路径,第二个参数是指定创建的新数据库所需磁盘空间的最小值。考虑OOM,把map_size改小,问题解决...

js中文本框如何获得焦点_weixin_33724570的博客-程序员宅基地

if((user.value == a.value) &amp;&amp; ((hex_md5(pass.value)) == b.value))&lt;!--如果输入的管理员帐号和密码正确,则新ID、密码框可以使用。原ID、密码框禁用。密码输入框里的内容用MD5加密过。跟数据库里匹配。--&gt;{var txkk = document.getElementById("txkk");&l...

用conda下载scrapy报错_code_双儿的博客-程序员宅基地

Error: Cannot link a source that does not exist.上网寻找解决方案,看了很多个博客,瞎捯饬一通,最后终于解决了。使用conda安装scrapy步骤:先下载Anaconda,配置好环境变量。在cmd中使用conda --version命令测试是否安装成功。ps:使用管理员身份。打开Anaconda Prompt 使用pip install scrapy安装scrapy。安装成功后,使用命令scrapy查看scrapy版本信息。我的解决方式:

php fpm maxchildren,【整理】php-fpm.conf中的pm.max_children到底应该设置为多少_任我心意的博客-程序员宅基地

折腾:期间,想要搞清楚:php-fpm.conf中的pm.max_children到底应该设置为多少因为:“错误三:资源耗尽LNMP 架构处理 php 时,是 nginx 直接调取后端的 php-fpm 服务,如果 nginx 的请求量偏高,而我们又没有给 php-fpm 配置足够的子进程,那么总有 php-fpm 资源耗尽的时候,一旦耗尽 nginx 则找不到 php-fpm,此时就会导致 50...

gitlab增加日志_lyuharvey的博客-程序员宅基地

2019独角兽企业重金招聘Python工程师标准&gt;&gt;&gt; ...

推荐文章

热门文章

相关标签