建网站做哪方面,重庆农村网站建设,太原市手机网站建设,网站文章好几天不收录当您的Java应用程序占用100#xff05;的CPU时#xff0c;您该怎么办#xff1f; 事实证明#xff0c;您可以使用内置的UNIX和JDK工具轻松找到有问题的线程。 不需要探查器或代理。 为了进行测试#xff0c;我们将使用以下简单程序#xff1a; public class Main {publi… 当您的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转义码表示颜色 –看不见的字符破坏了grep和cut类的工具。 幸运的是我找到了一个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 prio10 tid0x7f3bf800 nid0x6552 runnable [0x7f25c000]java.lang.Thread.State: RUNNABLEat java.util.regex.Pattern$Node.study(Pattern.java:3010) 没错 nid0x645a参数与top -H打印的线程ID相同。 当然不要太简单在jstack以十六进制打印时 top使用十进制表示法。 再次有一个简单的解决方案 printfx $ 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 prio10 tid0x7f3bf800 nid0x6552 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-1或Busy-2线程的堆栈跟踪在Pattern类中的不同位置但是从不Idle 。 参考 哪个Java线程消耗了我的CPU 来自我们的JCG合作伙伴 Tomasz Nurkiewicz来自Java和邻里博客。 翻译自: https://www.javacodegeeks.com/2012/08/which-java-thread-consumes-my-cpu.html