jstack使用实例:定位kafka线程占用大量cpu资源的问题
前言
越来越觉得,解决问题的思维方式比解决问题本身更重要。工作中永远会有新的问题出现,只有拥有正确、高效的思维方式,才能对这些问题一一迎刃而解。
jstack简介
它是jdk自带的一个jvm工具,可以查看和导出运行中java程序的java stack和native stack的信息。可以轻松得知当前线程的运行情况。
问题描述
前一段时间发现本机启动公司的一个java项目时,cpu资源被异常大量占用。我8c16t的锐龙7,打开任务管理器,cpu资源占用飙到了50%以上。
由于出现问题前引入了kafka,推测和kafka的消费线程有关。
定位问题
1. 定位问题线程tid。
首先我们要定位到是哪个线程占用这么多资源。
使用任务管理器只能看到进程pid,因此我们需要使用线程查看工具。win10下最好用的图形工具当然是process explorer了。

如图,找到应用java进程的pid=15120,并定位该进程里占用cpu最高的线程,tid=3880,对应16进制=f28。
2.导出jvm线程信息
随后使用jstack工具导出jvm所有的线程信息。命令如图

3.分析线程信息
打开1.txt,里面长这样:

在文件中搜索”f28″,找到对应的线程信息:

可以看出确实是kafka的一个线程,看方法栈里很多autoCommit的名字,似乎和kafka的自动提交有关。
4.分析代码
定位到maybeAutoCommitOffsetsAsync方法:
private void maybeAutoCommitOffsetsAsync(long now) {
if (autoCommitEnabled) {
if (coordinatorUnknown()) {
this.nextAutoCommitDeadline = now + retryBackoffMs;
} else if (now >= nextAutoCommitDeadline) {
this.nextAutoCommitDeadline = now + autoCommitIntervalMs;
doAutoCommitOffsetsAsync();
}
}
}
this.nextAutoCommitDeadline = now + autoCommitIntervalMs;
重点是这行代码,通过当前时间+autoCommitIntervalMs这个变量,更新了下次提交的时间,然后开始执行doAutoCommitOffsetsAsync方法。溯源了一下代码,这个变量是从配置文件属性:auto.commit.interval.ms获取的。
随后查看了下配置文件,这个值预设的间隔是2ms,间隔确实太低了。
5.修改配置
于是修改配置,改为5000ms,重启应用。cpu占用终于恢复了正常。