jstack 命令详解

jstack命令用来生成JVM中的线程快照(thread dump),其中包含有每个线程的方法调用栈以及其状态、锁信息等。其用法说明如下所示。
jdk-jstack命令
说明一下三个参数的含义:
-F:如果正常执行jstack命令没有响应(比如进程hung住了),可以加上此参数强制执行thread dump。
-m:除了打印Java的方法调用栈之外,还会输出native方法的栈帧。
-l:打印与锁有关的附加信息。使用此参数会导致JVM停止时间变长,在生产环境需慎用。

jstack是在线程级别定位JVM问题的利器,但前提是得读懂thread dump,我们举例说明。

线程快照

jdk-jstack命令
在每个线程的快照的第一行,包含有线程名、是否为守护线程、优先级、线程ID等信息,第二行则是线程状态,下面就是方法调用栈了。下图是Java线程状态转换的示意,老生常谈。
jdk-jstack命令
jstack线程快照中的状态与图示相同,只是没有NEW状态而已。我们逐一进行分析,在分析之前,先放出Java管程对象ObjectMonitor的简图。看官也可以通过我之前写的这篇文章来了解管程。
jdk-jstack命令

RUNNABLE

线程正在运行。如果在其调用栈中看到locked <地址>的提示,表示该方法正持有锁,即该线程位于Owner区内。

BLOCKED

线程处于阻塞状态,即正在等待锁被其他线程释放。在其调用栈的栈顶方法会看到waiting to lock <地址>的提示,表示该方法试图持有锁,线程正在Entry Set区等待。

WAITING

线程处于无限等待的状态。又分为两种情况:

  • on object monitor:线程已经获得锁,调用了不带超时参数的Object.wait()/Thread.join()方法,线程进入管程的Wait Set区。在其调用栈中会看到locked <地址>的提示。
  • parking:调用了LockSupport.park()方法,线程直接进入挂起状态(park是Unsafe提供的低级原语)。在其调用栈的栈顶方法会看到parking to wait for <地址>的提示。

TIMED_WAITING

线程处于有限等待的状态。它分为三种情况,除了与WAITING相同的on object monitor(获得锁并调用带超时的Object.wait()/Thread.join()方法)和parking(调用带超时的LockSupport.parkNanos()/parkUntil()方法)之外,还有一种sleep,即通过Thread.sleep()使线程睡眠。

通过分析线程快照的状态和调用栈,可以让我们快速地定位造成Java程序表现异常的症结,如死锁、热锁(很多线程竞争同一块临界区造成大量BLOCKED)、高CPU占用、I/O长时间阻塞(注意此时线程状态可能是RUNNABLE)等。下面举两个具体的例子。

相关文章:

  • 2022-12-23
  • 2022-01-29
  • 2022-01-08
  • 2022-01-08
  • 2022-01-08
  • 2022-01-08
  • 2022-01-08
猜你喜欢
  • 2021-05-25
  • 2022-01-08
  • 2022-01-08
  • 2022-01-08
  • 2021-05-22
  • 2021-07-06
相关资源
相似解决方案