线上CPU飚高(死循环,死锁...)?帮你迅速定位代码位置

商务办公
在Linux系统中,有一个守护进程(daemon)会定期把buffers中的数据写入的磁盘,也可以使用 sync 命令手动把buffers中的数据写入磁盘。使用buffers可以把分散的 I/O 操作集中起来,减少了磁盘寻道的时间和磁盘碎片。

[[262533]]

top基本使用

top 命令运行图:

 

***行:基本信息

 

第二行:任务信息

 

第三行:CPU使用情况

 

第四行:物理内存使用情况

 

buff/cache:

buffers 和 cache 都是内存中存放的数据,不同的是,buffers 存放的是准备写入磁盘的数据,而 cache 存放的是从磁盘中读取的数据

在Linux系统中,有一个守护进程(daemon)会定期把buffers中的数据写入的磁盘,也可以使用 sync 命令手动把buffers中的数据写入磁盘。使用buffers可以把分散的 I/O 操作集中起来,减少了磁盘寻道的时间和磁盘碎片。

cache是Linux把读取频率高的数据,放到内存中,减少I/O。Linux中cache没有固定大小,根据使用情况自动增加或删除。

第五行:交换区使用情况

 

Swap(内存交换区):

是硬盘上的一块空间。在内存不足的情况下,操作系统把内存中不用的数据存到硬盘的交换区,腾出内存来让别的程序运行。因此,开启swap会一定程度的引起 I/O 性能下降(阿里服务器默认不开)

第六行:进程详细信息

 

死循环

构造的代码如下:

  1. @RestController 
  2. @RequestMapping("top"
  3. public class ShowTopController { 
  4.  
  5.     private Object lock1 = new Object(); 
  6.     private Object lock2 = new Object(); 
  7.  
  8.     @RequestMapping("test"
  9.     public String test() { 
  10.         return "success"
  11.     } 
  12.  
  13.     @RequestMapping("loop"
  14.     public String loop() { 
  15.         System.out.println("start"); 
  16.         while (true) {} 
  17.     } 
  18.  
  19.     @RequestMapping("deadlock"
  20.     public String deadlock() { 
  21.         new Thread(() -> { 
  22.             synchronized (lock1) { 
  23.                 try{ 
  24.                     TimeUnit.SECONDS.sleep(1); 
  25.                 } catch (Exception e) {} 
  26.                 synchronized (lock2) { 
  27.                     System.out.println("thread1 over"); 
  28.                 } 
  29.             } 
  30.         }).start(); 
  31.         new Thread(() -> { 
  32.             synchronized (lock2) { 
  33.                 try{ 
  34.                     TimeUnit.SECONDS.sleep(1); 
  35.                 } catch (Exception e) {} 
  36.                 synchronized (lock1) { 
  37.                     System.out.println("thread2 over"); 
  38.                 } 
  39.             } 
  40.         }).start(); 
  41.         return "success"
  42.     } 

这里只介绍一下用到的top参数

先手动制造CPU飙高的场景,多执行几次,小编这里执行3次

  1. curl localhost:8080/top/loop 

执行top

 

jstack命令工具可以得到线程堆栈信息,根据这些线程堆栈信息,我们可以去检查Java程序出现的问题

看到pid为23757的进程CPU占用较高,执行如下命令

  1. jstack 23757 > loop.txt 

看看pid为23757的进程中线程的具体情况

  1. top -p 23757 -H 

当然你也可以使用交互命令

  1. top -p 23757 

然后再输入H,效果和上面一样

可以看到PID为23772,23773和23774的线程占用CPU较高

这里可能有人有疑惑,为什么线程也有PID啊?其实线程进程都会有自己的ID,这个ID就叫做PID,PID是不特指进程ID,线程ID也可以叫做PID

将10进制的23772转为16进制,因为jstack中PID用的是16进制

  1. printf "%x" 23772 
  2. 输出5cdc 

打开loop.txt文件,搜5cdc

 

可以看到线程一直在执行ShowTopController中的第23行,即

  1. while (true) {} 

好了定位到代码中的位置了,当然生产环境中肯定不会写一个死循环的,有可能在特殊场景下出现死循环,或执行一个方法特别慢,用这种方法很快就能找到代码位置。

死锁

接着访问

  1. curl localhost:8080/top/loop 

执行

  1. jstack 23757 > loop.txt 

打开loop.txt文件到***

 

 

看到发现一个死锁,死锁代码的位置描述的很清楚,生产环境发生的死锁当然没有这么简单,所有学会用这些命令排查还是很有必要的

本文转载自微信公众号「 Java识堂」,转载本文请联系Java识堂公众号。

责任编辑:武晓燕 来源: Java识堂
相关推荐

2022-03-31 09:00:47

高并发Log4j2java

2017-08-19 23:21:14

线上CPU定位

2019-07-24 11:52:11

CPU服务器面试官

2015-10-23 14:36:38

程序员起跑线

2013-06-06 13:34:56

HashMap线程不安全

2021-07-04 22:29:12

MySQL死锁云日志

2010-08-10 11:19:28

路由器故障

2010-07-29 08:41:11

路由器故障

2011-09-07 10:13:04

IPv6IPv4

2018-10-10 20:20:14

2017-02-22 15:19:17

服务器虚拟化优化虚拟环境

2020-12-17 07:39:30

HashMap死循环数据

2018-04-04 16:24:49

区块链数字货币比特币

2015-04-22 09:33:41

2023-11-15 18:53:06

线程客户端

2019-05-13 08:24:58

数据库MySQLInnoDB

2009-04-23 13:58:52

路由器定位故障

2010-04-26 13:30:21

服务器虚拟化

2020-09-29 15:24:07

面试数据结构Hashmap

2019-12-19 10:31:16

运维架构技术
点赞
收藏

51CTO技术栈公众号