当您的Java应用程序占用100%的CPU时,您该怎么办? 事实证明,您可以使用内置的UNIX和JDK工具轻松找到有问题的线程。 不需要探查器或代理。

为了进行测试,我们将使用以下简单程序:

public class Main {public static void main(String[] args) {new Thread(new Idle(), 'Idle').start();new Thread(new Busy(), 'Busy').start();}
}class Idle implements Runnable {@Overridepublic void run() {try {TimeUnit.HOURS.sleep(1);} catch (InterruptedException e) {}}
}class Busy implements Runnable {@Overridepublic void run() {while(true) {'Foo'.matches('F.*');}}
}

如您所见,它启动了两个线程。 Idle不消耗任何CPU(请记住,睡眠线程消耗内存,但不消耗CPU),而Busy占用整个内核,因为正则表达式的解析和执行是一个令人惊讶的复杂过程。 让我们运行该程序,然后将其忽略。 我们如何快速发现Busy是我们软件中有问题的部分? 首先,我们使用top来找出消耗大部分CPU的java进程的进程ID( PID )。 这很简单:

$ top -n1 | grep -m1 java

这将显示包含“ java ”语句的top输出的第一行:

22614 tomek     20   0 1360m 734m  31m S    6 24.3   7:36.59 java

第一列是PID,让我们提取它。 不幸的是,事实证明top使用ANSI转义码表示颜色 –看不见的字符破坏了grepcut类的工具。 幸运的是,我找到了一个Perl脚本来删除这些字符 ,并最终能够提取用尽CPU的java进程的PID:

$ top -n1 | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' '

cut -f1 -d' '调用只是将第一个值从以空格分隔的列中取出:

22614

现在,当我们遇到有问题的JVM PID时,我们可以使用top -H查找有问题的Linux线程。 -H选项显示与进程相对的所有线程的列表,PID列现在表示内部Linux线程ID:

$ top -n1 -H | grep -m1 java
$ top -n1 -H | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' '

输出令人惊讶地相似,但是第一个值现在是线程ID:

25938 tomek     20   0 1360m 748m  31m S    2 24.8   0:15.15 java
25938

因此,我们有一个繁忙的JVM的进程ID和Linux线程ID(很可能来自该进程)消耗了我们的CPU。 这是最好的部分:如果查看jstack输出(在JDK中可用),则每个线程的名称旁边都会印有一些神秘的ID:

'Busy' prio=10 tid=0x7f3bf800 nid=0x6552 runnable [0x7f25c000]java.lang.Thread.State: RUNNABLEat java.util.regex.Pattern$Node.study(Pattern.java:3010)

没错, nid=0x645a参数与top -H打印的线程ID相同。 当然,不要太简单,在jstack以十六进制打印时, top使用十进制表示法。 再次有一个简单的解决方案, printf'%x' :

$ printf '%x' 25938
6552

让我们将我们现在拥有的所有内容包装到一个脚本中并合并结果:

#!/bin/bash
PID=$(top -n1 | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' ')
NID=$(printf '%x' $(top -n1 -H | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' '))
jstack $PID | grep -A500 $NID | grep -m1 '^$' -B 500

PID持有java PID, NID持有线程ID,很可能来自该JVM。 最后一行只是转储给定PID的JVM堆栈跟踪,并过滤(使用grep )具有相匹配的nid的线程。 猜猜它有什么用:

$ ./profile.sh
'Busy' prio=10 tid=0x7f3bf800 nid=0x6552 runnable [0x7f25c000]java.lang.Thread.State: RUNNABLEat java.util.regex.Pattern$Node.study(Pattern.java:3010)at java.util.regex.Pattern$Curly.study(Pattern.java:3854)at java.util.regex.Pattern$CharProperty.study(Pattern.java:3355)at java.util.regex.Pattern$Start.<init>(Pattern.java:3044)at java.util.regex.Pattern.compile(Pattern.java:1480)at java.util.regex.Pattern.<init>(Pattern.java:1133)at java.util.regex.Pattern.compile(Pattern.java:823)at java.util.regex.Pattern.matches(Pattern.java:928)at java.lang.String.matches(String.java:2090)at com.blogspot.nurkiewicz.Busy.run(Main.java:27)at java.lang.Thread.run(Thread.java:662)

多次运行脚本(或使用watch ,请参见下文)将在不同位置捕获Busy线程,但是几乎总是在正则表达式解析中进行–这是我们有问题的部分!

多线程

如果您的应用程序具有多个需要CPU的线程,则可以使用watch -n1 ./profile.sh命令watch -n1 ./profile.sh运行一次脚本并获取半实时堆栈转储,这很可能来自不同的线程。 使用以下程序进行测试:

new Thread(new Idle(), 'Idle').start();
new Thread(new Busy(), 'Busy-1').start();
new Thread(new Busy(), 'Busy-2').start();

您将看到Busy-1Busy-2线程的堆栈跟踪(在Pattern类中的不同位置),但是从不Idle

参考: 哪个Java线程消耗了我的CPU? 来自我们的JCG合作伙伴 Tomasz Nurkiewicz,来自Java和邻里博客。

翻译自: https://www.javacodegeeks.com/2012/08/which-java-thread-consumes-my-cpu.html

哪个Java线程消耗了我的CPU?相关推荐

  1. 【JVM性能调优】使用jstack找出最耗CPU的java线程

    jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体的代码,所以它在JVM性能调优中很常见.下面我们在找出某个java进程中最耗CPU的线程,并定位堆栈信息,使用到的命令有:ps.top.p ...

  2. Windows上的Java线程CPU分析

    本文将为您提供一个教程,介绍如何在Windows OS上快速查明Java线程贡献者与CPU严重问题有关. Windows与Linux,Solaris和AIX等其他操作系统一样,使您可以在进程级别监视C ...

  3. java线程切换消耗时间_cpu性能消耗分析

    在Linux中,CPU主要用于中断.内核以及用户进程的任务处理,优先级为中断>内核>用户进程,在学习如何分析CPU消耗状况前.先要掌握三个重要的概念 1.上下文切换 每个CPU在同一时间只 ...

  4. java线程 cpu占用率_多线程程序 怎样查看每个线程的cpu占用

    可以用下面的命令将 cpu 占用率高的线程找出来: ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu 这个命令首先指定参数'H',显示线程相关的 ...

  5. 如何定位cpu占用率高的java线程

    如何定位cpu占用率高的java线程 工具: 1 jstack:jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项&q ...

  6. java 线程 cpu_java程序中线程cpu使用率计算

    最近确实遇到题目上的刚需,也是花了一段时间来思考这个问题. cpu使用率如何计算 计算使用率在上学那会就经常算,不过往往计算的是整个程序执行的时间段,现在突然要实时计算还真有点无奈,时间段如何选择是个 ...

  7. java 线程什么时候结束_java线程什么时候让出cpu?

    Thread.sleep(); sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep ...

  8. 怎样分析java进程占cpu_java进程占用cpu过高分析是哪些线程

    拿hbase基准测试列子来分析哪些线程使用比较高的cpu,环境是linux,基准测试命令: hbase org.apache.hadoop.hbase.PerformanceEvaluation  - ...

  9. Top命令找出CPU占用较高的Java线程信息

    Top命令找出CPU占用较高的Java线程信息 由于种种原因导致生产环境的应用CPU占用奇高, 这个时候就需要确定到底是哪些线程占用了较高的CPU, 然后再做针对性的优化, 可以使用jconsole/ ...

最新文章

  1. seaborn可视化散点图并自定义数据轴标签(X轴和Y轴的轴标签,Change X Y Axis Labels to a Seaborn Plot)
  2. superset的安装和使用--docker
  3. seata 如何开启tcc事物_如何能在实战中完成分布式事务?知道这些点很重要
  4. JavaScript中getBoundingClientRect()方法详解
  5. future java 原理_Java线程池FutureTask实现原理详解
  6. mybatis转义反斜杠_Shell echo命令:输出字符串
  7. 牛客 - 焦糖布丁(线性基+博弈)
  8. python 新闻摘要_每日新闻摘要:Microsoft内部禁止应用程序,这样就可以了
  9. Requests库实战(二)---破解百度翻译
  10. C++ 执行cmd命令 并获取输出
  11. byte数组穿换成pcm格式_形象地介绍DSD的编解码原理及和PCM的区别
  12. python -- lambda表达式
  13. excite-punastranvirtual.lab振动噪声仿真
  14. cgi java编程_Java的CGI数据编码改如何编写
  15. 监控视频转发方案探讨-内网转外网
  16. Linux终端下输出二维码
  17. 2篇word文档比较重复率_【软件】PDF转word黑科技 快来get!
  18. Linux系统下ActivityMQ的安装
  19. 自考多媒体计算机技术,自考多媒体计算机技术.doc
  20. quartus基本操作

热门文章

  1. 【1】flink-source读取数据
  2. spring-kafka整合:DefaultKafkaProducerFactory默认kafka生产者工厂介绍
  3. internet地址java表示
  4. tomcat中配置jndi数据源以便spring获取
  5. Java IO(BIO, NIO, AIO) 总结
  6. 使用文本编辑器和jdk_JDK 14:记录,文本块等
  7. java 读取集合到流中_Java 10:将流收集到不可修改的集合中
  8. mwc校准油门_编写下载服务器。 第五部分:油门下载速度
  9. java使用泛型后消除泛型_如何以及何时使用泛型
  10. hibernate工厂模式_Hibernate锁定模式–乐观锁定模式如何工作