JVM 命令指北(4)-jstack 命令

1. 功能简介

jstack 用于打印出给定的 Java进程ID 或远程调试服务的线程快照。线程快照是 Java 虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环造成的长时间等待。 通过 jstack 查看各个线程的调用堆栈,就可以知道停顿的线程到底在做什么,或者等待什么资源。 如果 Java 程序崩溃生成core文件jstack工具也可以获取 core 文件的 Java方法栈和本地方法栈的信息,从而可以直达事故现场分析出程序是如何崩溃的。另外需注意机器上当前登录用户和 Java 进程启动用户不是同一个时,无法使用该命令

  • 需要注意的问题
    不同的 JAVA 虚机的线程 DUMP 的创建方法和文件格式是不一样的,不同的 JVM 版本, dump信息也有差别。在实际运行中,往往一次 dump的信息,还不足以确认问题。建议产生三次 dump信息,如果每次 dump都指向同一个问题,才能确定问题的典型性

2. 使用方式

命令格式参数说明
jstack [ option ] pidpid 为 Java 应用程序的进程号,连接到正在运行的进程
jstack [ option ] executable coreexecutable 为产生core dump的 java可执行程序,core为打印出的core文件,该命令可连接到核心文件
jstack [ option ] [ server-id@]remote-hostname-or-IPremote-hostname-or-ip 是远程debug服务器的名称或IP,server-id是唯一id,假如一台主机上有多个远程debug服务会需求区分
Options功能
-F当线程没有响应的时候强制打印栈信息
-m打印 Java 和 native c/c++ 框架的所有栈信息
-l长列表. 打印关于锁的附加信息,例如属于 java.util.concurrent 的 ownable synchronizers 列表

常见的使用方式如下

// 打印指定 Java 进程的栈信息
jstack -l 44295
// 输出指定 Java 进程的栈信息到 log 文件中
jstack -l 44295 > ~/44295.log

3. 分析注意

3.1 线程状态

通过 jstack 命令来分析线程的情况,首先要知道线程都有哪些状态,以下状态是查看线程堆栈信息时可能会看到的:

RUNNABLE: 在虚拟机内执行的
BLOCKED: 受阻塞并等待监视器锁,通常是多条线程争夺 synchronized 锁住资源失败触发
WATING:无限期等待另一个线程执行特定操作
TIMED_WATING:有时限的等待另一个线程的特定操作,通常由 sleep(n) 及定时任务触发
TERMINATED:已退出的
在这里插入图片描述

3.2 线程信息的格式

参考 Java 对象锁的 Monitor 实现,可以知道一个 Monitor 在某个时刻,只能被一个线程拥有,拥有锁的线程就是 Active Thread,而其它线程都是 Waiting Thread,分别在两个队列 EntrySetWaitSet 里面等待。在 EntrySet中等待的线程状态是 Waiting for monitor entry,表示等待获取锁;而在 WaitSet中等待的线程状态是 in Object.wait(),表示获得锁成功后又释放,等待被唤醒

一个典型线程信息如下,可以看到在第二行中标出的是线程状态 WAITING (on object monitor),表示在等待获取 Monitor 对象,而第一行的in Object.wait() 则是等待状态产生的原因,可以知道是线程当前执行条件不满足,自己调用了 wait() 方法放弃锁,等待被 notify()。而waiting on <no object reference available> 则是当前线程对 Monitor 锁的操作状态,表示使用synchronized申请对象锁成功后,释放锁并在WaitSet 里面等待被唤醒

“Disposer” #105 daemon prio=10 os_prio=31 cpu=35.51ms elapsed=241580.14s tid=0x00007fa74fb0f800 nid=0x20e87 in Object.wait() [0x000070000a46c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.4/Native Method)
- waiting on <no object reference available>
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.4/ReferenceQueue.java:155)
- waiting to re-lock in wait() <0x00000007493fc428> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.4/ReferenceQueue.java:176)
at com.sun.webkit.Disposer.run(javafx.web@11.0.4/Disposer.java:122)
at java.lang.Thread.run(java.base@11.0.4/Thread.java:834)
.
Locked ownable synchronizers:
- None

线程对 Monitor 对象的操作状态意义
locked <地址> 目标使用synchronized申请对象锁成功,监视器的拥有者
waiting to lock <地址> 目标使用synchronized申请对象锁未成功,在EntrySet 队列等待
waiting on <地址> 目标使用synchronized申请对象锁成功后,释放锁在WaitSet 区等待
parking to wait for <地址> 目标等待获取锁时调用 park() 挂起线程
线程状态描述线程状态
runnable状态一般为RUNNABLE
in Object.wait()WaitSet等待区等待,状态为 WAITING 或 TIMED_WAITING
waiting for monitor entryEntrySet 进入区等待,状态为 BLOCKED
waiting on conditionWaitSet等待区等待,线程被 park
sleeping休眠的线程,调用了Thread.sleep()

3.3 重点信息

搜索关键字含义
Deadlock死锁,重点关注
Waiting on condition等待资源,重点关注
Waiting on monitor entry等待获取监视器,重点关注
Blocked阻塞,重点关注
  1. Deadlock关键字
    这个一般指多个线程调用时,自己占用了一部分资源,又需要请求对方占用的资源导致无限期等待对方释放资源的情况。这种情况堆栈写的会很明显,它会打印 Found one Java-level deadlock,然后指出造成死锁的线程的信息

  2. Blocked 关键字
    线程状态是 Blocked,说明线程等待资源超时。此时可查看其 waiting to lock <0x0000000xxxxxxx>信息,在 dump 日志里查找这个地址字符串,如发现有大量线程都在等待给这个地址上锁,可能在代码级别已经存在冲突的调用。此时如果能在日志里找到谁获得了这个锁(关键字locked <0x0000000xxxxxxx>),则可以有效找到事故现场

  3. Wait on condition 关键字
    该状态表示等待资源,或等待某个条件的发生,具体原因需结合堆栈信息来分析。最常见的情况就是线程处于sleep状态,等待被唤醒

    • 如果线程是用户线程,则证明该线程正在等待资源。一般是大量读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取
    • 如果发现有大量的线程都在处在 Wait on condition,从线程 stack 看正等待网络读写,这可能是一个网络瓶颈的征兆,因为网络阻塞导致线程无法执行。一种情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常到达
  4. 持续运行的IO
    IO 操作可以在 RUNNABLE状态达成阻塞,例如数据库死锁、网络读写。 需要格外注意对 IO 线程真实状态的分析,比如readLine()造成的 IO 阻塞,一般被捕捉到RUNNABLEIO 调用都是有问题的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值