Java工具-利用jstack定位Java线程堆栈信息(一)

一、概述

  JDK本身提供了许多方便的性能调优及监控的小工具,这些小工具虽然没有说是官方的标准工具,但自从Java诞生这么多年,这些工具一直在被人使用,不得不说这是JDK给开发者的福利,这些工具包含但不仅限于:jstack、jps、jmap、jConsole、jstat等等。
 由于前些时候用到了jstack这个工具,所以今天来简单总结下jstack的使用。

二、jstack使用

首先,jstack会生成JVM当前时刻的线程快照,然后我们可以通过它查看某个Java进程内的线程堆栈信息,通常来说,当线上CPU使用率较高的时候,我们可以通过jstack查询占用CPU较高的一些线程的使用情况,比如发生了死锁,线程阻塞等相关操作。一般情况下,jstack会配合其他命令一块进行操作,比如top,ps等命令。我们先来看下使用jstack命令的一些步骤。

1. 查询占用CPU最高的进程

首先,我们通过top命令查询当前CPU的使用情况,top命令前面已详细说过,这里不多说,直接输入命令:top

这里我们可以看到各个进程对CPU的使用占比,并且可以根据top相关命令进行排序。

2. 查询该进程下占用CPU最高的线程

接下来我们可以根据进程id查询该进程下占用CPU比较高的线程,输入命令:top -Hp PID,其中PID是上面的那个进程id,比如我们这个的:top -Hp 12386

如果对PS命令比较熟的,还可以直接通过:ps H -eo pid,tid,pcpu | sort -n -k 3 | tail -10 来定位到相关线程:

如果想看下线程的详细信息,还可以通过:cat /proc/进程号/task/线程号/status来查看。如果需要查询该进程下所有的线程,我们还可以通过pstree命令,以树的形式展示:

3. 使用jstack获取对应的线程信息

这里我们获取到了对应的线程id,由于jstack输出中的线程id是16进制的,所以需要先将线程id转为16进制:

然后使用jstack命令查看对应的堆栈信息:jstack $pid|grep -A N $nid,其中此处的pid指的是进程号,而nid指的是该进程下占用最多的线程号,比如:jstack 12386|grep -A 30 30c6

这里来简单看下各数据项的含义:

  • 最前面的是线程名称;当我们通过Thread来创建线程的时候,线程会被命名为Thread-(序号);当我们使用连接池通过ThreadFactory来创建线程时,线程会被命名为 pool-(序号)-thread-(序号)
  • tid,指的是线程id;
  • prio,指的是线程优先级,值越大优先级越高;
  • os_prio,表示的对应操作系统线程的优先级,由于并不是所有的操作系统都支持线程优先级,所以可能会出现都为0的情况;
  • nid,操作系统映射的线程id,每一个java线程都有一个对应的操作系统线程;
  • java.lang.Thread.State:RUNNABLE,当前线程的状态;如果是WATTING状态,后面会跟上调用哪个方法导致的watting状态;
  • 另外线程是否持有锁信息等,如果持有锁,则是locked<>;而如果是正在等待获取锁,则是 wating for <>;

grep命令中的 -A 表示显示后面若干行,前面也已经学习过这个命令,不多说了。本例中可以看到的是Kafka一直在消费数据,正常来说,除了确实是那种需要密集计算的应用之外,一个应用的CPU都不会太高,除非出现了一些其他的异常情况。

另外,我们还可以将该进程的相关线程信息导出到stack.dump文件中,然后我们可以在这个文件中查看每个线程的具体状态:jstack pid(进程pid)>stack.dump,这里就不多说了。

三、jstack语法

jstack本身的使用并不复杂,我们来看下它的一些参数:

deploy@127.0.0.1:~$ jstack -help
Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

其中参数文档已经说的很明确了,这里再说下:

  • -l 会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁的持有情况;
  • -m 不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法);

比如说:

deploy@127.0.0.1:~$ jstack -l 27075 | grep -A 50 6a15
"pool-1-kafka@thread-1" #45 prio=5 os_prio=0 tid=0x00007f63b1f18000 nid=0x6a15 runnable [0x00007f6324c6b000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    ...
    - locked <0x000000072028f2a8> (a sun.nio.ch.Util$2)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    ...
    at org.apache.kafka.clients.consumer.KafkaConsumer.pollOnce(KafkaConsumer.java:1096)
    at org.apache.kafka.clients.consumer.KafkaConsumer.poll(KafkaConsumer.java:1043)
    at ****.KafkaConsumerWorker.run(KafkaConsumerWorker.java:39)
    ...
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - <0x000000072012cbb0> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"Curator-PathChildrenCache-0" #44 daemon prio=5 os_prio=0 tid=0x00007f63b1ce4800 nid=0x6a14 waiting on condition [0x00007f6324538000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007201df280> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None

这里可以看到当前线程类型:daemon ,当前线程正在等待获取锁 0x00000007201df280,并且当前线程没有持有锁;不过我们更多的是关注用户线程。

这里,涉及到了Locked ownable synchronizers,这里其实有点没看懂,如果表示是该线程锁定的资源的话,那上面locked就会展示了;在stackoverflow上看了下,"ownable synchronizers" list只会出现write lock,而不会出现read lock;然后看了下官方文档:

An ownable synchronizer is a synchronizer that may be exclusively owned by a thread and uses AbstractOwnableSynchronizer (or its subclass) to implement its synchronization property. ReentrantLock and ReentrantReadWriteLock are two examples of ownable synchronizers provided by the platform.

不过还是没有看太懂,以后看到的时候再补充吧(TODO)。
有关Locked ownable synchronizers的说明,可以参考:what-is-locked-ownable-synchronizers-in-thread-dump-stackoverflow.com

四、jstack注意事项

在使用jstack之前,我们肯定是需要了解线程的几种状态的,而在这里我们需要关注的一般有如下几种:

  • RUNNABLE,线程处于执行中;一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,或者正在进行资源的操作等;
  • BLOCKED,线程阻塞;
  • WAITING,线程正在等待中;Waiting on condition(等待资源或条件),Waiting for monitor entry(waiting to lock ,等待获取锁);
  • Deadlock ,死锁;一个线程锁了某个资源A,等待另一个资源B;而另一个线程恰好锁了这个被等待的资源B,在等待资源A;

另外,还需要注意:

  • 如果我们要通过dump来查看问题的话,那一次dump可能不足以确认问题,可以产生多次 dump信息,如果每次 dump都指向同一个问题,我们基本就可以确定问题的所在。
  • 使用jstack的时候,需要对应的服务器权限,需要注意,如果没有权限的话,会提示你不允许的操作。

而有关jstack更多操作,可以参考以下链接:
JVM性能分析工具jstack介绍
JVM故障分析系列之四:jstack生成的Thread Dump日志线程状态
jstack线程dump输出状态解释

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容