在本教程中,我们创建了一个简单的Java程序,使您可以逐步学习该技术。
故障排除工具
本教程将在下面使用以下工具:
- (查明高CPU线程贡献者)
- (用于代码级别的线程关联和根本原因分析)
高CPU模拟器Java程序
下面的简单程序只是循环并创建新的String对象。 这将使我们能够按线程分析执行此CPU。 我建议您将其导入您选择的IDE中,例如Eclipse并从那里运行它。 执行Windows计算机后,应立即观察到CPU数量的增加。
package org.ph.javaee.tool.cpu;
/**
* HighCPUSimulator
* @author Pierre-Hugues Charbonneau
* http://javaeesupportpatterns.blogspot.com
*
*/
public class HighCPUSimulator {
private final static int NB_ITERATIONS = 500000000;
// ~1 KB data footprint
private final static String DATA_PREFIX = "datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatad
atadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadata";
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("HIGH CPU Simulator 1.0");
System.out.println("Author: Pierre-Hugues Charbonneau");
System.out.println("http://javaeesupportpatterns.blogspot.com/");
try {
for (int i = 0; i < NB_ITERATIONS; i++) {
// Perform some String manipulations to slowdown and expose looping process...
String data = DATA_PREFIX + i;
}
} catch (Throwable any) {
System.out.println("Unexpected Exception! " + any.getMessage()
+ " [" + any + "]");
}
System.out.println("HighCPUSimulator done!");
}
}
步骤#1 –启动流程浏览器
Process Explorer工具以可视方式动态显示CPU使用情况。 这对于实时分析非常有用。 如果您需要每个线程在CPU上的历史数据,则还可以将Windows perfmon与%Processor Time&Thread Id数据计数器一起使用。 您可以从下面的链接下载Process Explorer:
http://technet.microsoft.com/zh-cn/sysinternals/bb896653
在我们的示例中,您可以看到在执行示例程序之后,Eclipse javaw.exe进程现在使用了约25%的CPU利用率。
步骤#2 –启动Process Explorer的Threads视图
下一步是显示javaw.exe进程的“线程”视图。 只需右键单击javaw.exe进程,然后选择“属性”。 将根据以下快照打开“线程”视图:
- 第一列是线程ID(十进制格式)
- 第二列是每个线程使用的CPU利用率%–
- 第三列也是另一个计数器,指示线程是否正在CPU上运行
在我们的示例中,我们可以看到罪魁祸首是使用约25%CPU的线程ID#5996。
步骤#3 –生成JVM线程转储
此时,Process Explorer将不再有用。 目的是查明一个或多个Java线程,这些线程消耗了我们实现的大部分Java进程CPU利用率。 为了进入分析的下一个层次,您将需要捕获JVM线程转储。 这将使您能够将线程ID与线程堆栈跟踪相关联,从而可以查明这种处理类型正在消耗如此多的CPU。
JVM线程转储的生成可以通过几种方式完成。 如果您使用的是JRockit VM,则可以按照以下示例使用jrcmd工具:
获得线程转储数据后,只需搜索线程ID并找到您感兴趣的线程堆栈跟踪。
在我们的示例中,从Eclipse触发的线程“主线程”被暴露为主要罪魁祸首,而这正是我们想要演示的。
Main Thread id=1 idx=0x4 tid=5996 prio=5 alive, native_blocked
at org/ph/javaee/tool/cpu/HighCPUSimulator.main
(HighCPUSimulator.java:31)
at jrockit/vm/RNI.c2java(IIIII)V(Native Method)
-- end of trace
步骤#4 –分析罪魁祸首的线程堆栈跟踪并确定根本原因
此时,您应该具备进行根本原因分析所需的一切。 您将需要检查每个线程堆栈跟踪,并确定要处理的问题类型。 最后一步通常是您将花费大部分时间的地方,问题可能很简单(例如无限循环),也可能很复杂(例如与垃圾回收相关的问题)。
在我们的示例中,线程转储确实揭示了CPU的高CPU数量来自第31行附近的示例Java程序。正如所料,它确实揭示了我们为本教程专门设计的循环条件。
for (int i = 0; i < NB_ITERATIONS; i++) {
// Perform some String manipulations to slowdown and expose looping process...
String data = DATA_PREFIX + i;
}
我希望本教程可以帮助您了解如何分析和帮助查明Windows OS上Java CPU问题的根本原因。 请继续关注更多更新,下一篇文章将为您提供Java CPU故障排除指南,包括如何处理最后的分析步骤以及常见问题模式。
参考: Java EE支持模式和Java教程博客中的JCG合作伙伴 Pierre-Hugues Charbonneau在Windows上的Java线程CPU分析 。