window 查找 java 进程中占用cpu比较高的线程
概述
公司内部的一个产品 (java 开发的) 运行在 window 虚拟机上,运行一段时间后CPU飙升,然后想查看是哪个线程占用。 折腾了一下午,终于定位到该线程。
下面我们通过两种方式定位到占用cpu比较高的线程。
- 使用Process Explorer,第三方工具定位,使用比较简单,容易上手。
- 使用window自带的perfmon 性能监控工具进行监控,功能强大,但稍微有点复杂。
示例程序
public class ThreadCpuTest {
public static void main(String[] args) {
Thread busyTask = new Thread(() -> {
for (;;) {
double a = new Random().nextDouble();
double b = new Random().nextDouble();
double c = a * b;
}
});
busyTask.setName("busy task");
busyTask.start();
Thread lazyTask = new Thread(() -> {
for (;;) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
});
busyTask.setName("lazy task");
lazyTask.start();
}
}
运行该示例,然后使用监控工具定位到那个线程CPU使用率高。
1. Process Explorer 使用
- 第一步: 获得该程序的进程ID
通过 jps 可以查看到 我们运行的程序的进程号为 “11964”
- 第二步: 打开Process Explorer工具
下面我们通过 Process Explorer 工具进行查看 该进程中所有的线程。
如果你没有 Process Explorer ,点击下面连接,进行下载。 点击 https://docs.microsoft.com/zh-cn/sysinternals/downloads/process-explorer 地址下载 Process Explorer
打开Process Explorer 后,界面如下:
- 第三步: 查找进程号为“11964”的进程
通过 jps 命令查看的进程号为 “11964”。然后在 Process Explorer中找到该进程。
- 第四步: 打开该进程Properties界面 然后选中该进程,双击或右键 选择“Properties...”
- 第五步: 选中“Threads”标签页,查看线程统计信息
选中 Threads 标签页。 发现线程ID为“20024” 的线程占用cpu比较高。
- 第六步: 线程ID转换成十六进制 然后我们把 十进制的 “20024” 转换为 十六进制的“4E38”。
- 第七步: dump线程信息 jstack 11964 > thread_dump.txt
- 第八步: 查找线程ID为“4E38”的线程
从线程的名字中,我们发现该线程的名字是“busy_task”。
然后就可以找到该线程,查看该线程是什么原因大量占用CPU,剩下的就是改程序的事情了
2. Perfmon 使用
- 第一步: 首先使用 jps 获取当前程序运行的进程ID
进程ID:“8880”
- 第二步: 打开perfmon 性能监视器
- 第三步: 打开添加计数器页面
- 第四步: 添加计数器
在左上部分找中,到Thread,选中 %Processor Time和 ID Thread 两个选项。 在左下部分中(选定对象的实例),找到所有“javaw”选中,点击添加按钮,然后显示如右半部分效果。
- 第五步: 切换报告显示方式
- 第六步: 查找使用CPU比较高的线程
从图中发现线程ID为“10320”的线程,占用CPU比较高。
- 第七步: 线程ID 转换成十六进制
线程ID 转换成十六进制为“2850”
- 第八步: dump 线程信息
- 第九步: 查找线程ID为“2850”的线程
从线程堆栈信息中可以看出该线程为“busy_task”线程。
- 浅谈webp
- 3385: [Usaco2004 Nov]Lake Counting 数池塘
- 2761: [JLOI2011]不重复数字(平衡树)
- 无图片字体icon
- 数据结构(三):栈与队列
- 3555: [Ctsc2014]企鹅QQ
- 3381: [Usaco2004 Open]Cave Cows 2 洞穴里的牛之二
- 3097: Hash Killer I
- 3390: [Usaco2004 Dec]Bad Cowtractors牛的报复
- 1684: [Usaco2005 Oct]Close Encounter
- 算法模板——Dinic最小费用最大流
- 算法模板——Dinic网络最大流 1
- SQL Server 使用全文索引进行页面搜索
- 2764: [JLOI2011]基因补全
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP获取中文拼音首字符方法
- PHP_MySQL笔试题目一
- nginx+nginx-upsync-module实现动态负载及自定义验证
- np.diff函数
- PHP对Json字符串解码返回NULL的一般解决方案
- 记一次 Istio 云数据库连接失败的错误排查过程
- PHP对抗web扫描器的脚本技巧
- MTO Jmetal IGD计算BUG
- 《算法》读书笔记:1.1 基础编程模型
- 《剑指 offer》刷题记录之:查找和排序
- numpy 计算路线距离
- 自然语言处理中的预训练模型(下)
- MySQL性能优化的最佳20+条经验
- 《剑指 offer》刷题记录之:回溯法
- 《剑指 offer》刷题记录之:动态规划与贪婪算法