37 jstack 的输出结果分析

Posted 蓝风9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了37 jstack 的输出结果分析相关的知识,希望对你有一定的参考价值。

前言

之前看到过这样的几篇帖子 

dump 中 waiting on condition、parking to wait for 应该怎么理解

为什么jstack dump 出来的线程的线程为什么都是000结尾的。

是关于 jstack 的输出结果的意义  

之前是 记录了 todo, 需要整理一下 

呵呵 了解这个 对于一些 简单的 vm 调试还是很有帮助的 

测试用例

package com.hx.test07;

import com.hx.test04.Test18DoubleCheckSingleton;
import sun.misc.Unsafe;

import java.util.concurrent.locks.LockSupport;

/**
 * JStackLog
 *
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2020-07-05 11:10
 */
public class Test08JStackLog 

  // Test08JStackLog
  public static void main(String[] args) 

    Object lock = new Object();
    Unsafe unsafe = Test18DoubleCheckSingleton.getUnsafe();

    new Thread("sleepThread") 
      @Override
      public void run() 
        synchronized (lock) 
          try 
            Thread.sleep(1000 * 1000);
           catch (Exception e) 
            e.printStackTrace();
          
        
      
    .start();

    new Thread("waitThread") 
      @Override
      public void run() 
        synchronized (lock) 
          try 
            lock.wait();
           catch (Exception e) 
            e.printStackTrace();
          
        
      
    .start();


    new Thread("parkThread") 
      @Override
      public void run() 
        LockSupport.park(lock);
      
    .start();

    new Thread("parkThread02") 
      @Override
      public void run() 
        LockSupport.park();
      
    .start();

    new Thread("runnableThread") 
      @Override
      public void run() 
        int i = 0;
        while (true) 
          i++;
        
      
    .start();

  


jstack 查看 Test08JStackLog 的栈帧信息 

"runnableThread" #17 prio=5 os_prio=31 tid=0x00007f809a8bb000 nid=0x9603 runnable [0x00007000092a8000]
   java.lang.Thread.State: RUNNABLE
	at com.hx.test07.Test08JStackLog$6.run(Test08JStackLog.java:97)

"parkThread" #16 prio=5 os_prio=31 tid=0x00007f809c000800 nid=0x6d03 waiting on condition [0x00007000091a5000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park(java.base/Native Method)
	at java.util.concurrent.locks.LockSupport.park(java.base/LockSupport.java:323)
	at com.hx.test07.Test08JStackLog$5.run(Test08JStackLog.java:88)

"parkThreadLockObj" #15 prio=5 os_prio=31 tid=0x00007f809a8b9800 nid=0x6c03 waiting on condition [0x00007000090a2000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park(java.base/Native Method)
	- parking to wait for  <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)
	at java.util.concurrent.locks.LockSupport.park(java.base/LockSupport.java:194)
	at com.hx.test07.Test08JStackLog$4.run(Test08JStackLog.java:81)

"waitThreadInQueue" #14 prio=5 os_prio=31 tid=0x00007f8099025800 nid=0x6b03 waiting for monitor entry [0x0000700008f9f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.hx.test07.Test08JStackLog$3.run(Test08JStackLog.java:69)
	- waiting to lock <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)

"sleepThread" #13 prio=5 os_prio=31 tid=0x00007f8099850800 nid=0x9903 waiting on condition [0x0000700008e9c000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(java.base/Native Method)
	at com.hx.test07.Test08JStackLog$2.run(Test08JStackLog.java:55)
	- locked <0x00000007bfbc2b80> (a com.hx.test07.Test08JStackLog)
	- locked <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)

"waitThreadAcquired" #12 prio=5 os_prio=31 tid=0x00007f809a8b8800 nid=0x6903 in Object.wait() [0x0000700008d99000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(java.base/Native Method)
	- waiting on <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)
	at java.lang.Object.wait(java.base/Object.java:516)
	at com.hx.test07.Test08JStackLog$1.run(Test08JStackLog.java:41)
	- waiting to re-lock in wait() <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)

这里面的内容主要是分为了两个部分, 一个是线程部分的信息 

另外一个是 当前线程的栈帧部分的信息 

线程的信息

我们关注的几个线程信息如下 

"runnableThread" #17 prio=5 os_prio=31 tid=0x00007f809a8bb000 nid=0x9603 runnable [0x00007000092a8000]
   java.lang.Thread.State: RUNNABLE

"parkThread" #16 prio=5 os_prio=31 tid=0x00007f809c000800 nid=0x6d03 waiting on condition [0x00007000091a5000]
   java.lang.Thread.State: WAITING (parking)

"parkThreadLockObj" #15 prio=5 os_prio=31 tid=0x00007f809a8b9800 nid=0x6c03 waiting on condition [0x00007000090a2000]
   java.lang.Thread.State: WAITING (parking)

"waitThreadInQueue" #14 prio=5 os_prio=31 tid=0x00007f8099025800 nid=0x6b03 waiting for monitor entry [0x0000700008f9f000]
   java.lang.Thread.State: BLOCKED (on object monitor)

"sleepThread" #13 prio=5 os_prio=31 tid=0x00007f8099850800 nid=0x9903 waiting on condition [0x0000700008e9c000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)

"waitThreadAcquired" #12 prio=5 os_prio=31 tid=0x00007f809a8b8800 nid=0x6903 in Object.wait() [0x0000700008d99000]
   java.lang.Thread.State: WAITING (on object monitor)

以 runnableThread 为例, 下图输出了线程的 名称, threadId, priority, last_java_sp(mask 掉了最右边的12个bit), java线程的状态 

上图中的 Thread::print_on 输出了 线程的 native_priority, tid(threadOop 对应的 JavaThread 的地址), os线程的状态 

线程的栈帧信息

"runnableThread" #17 prio=5 os_prio=31 tid=0x00007f809a8bb000 nid=0x9603 runnable [0x00007000092a8000]
   java.lang.Thread.State: RUNNABLE
	at com.hx.test07.Test08JStackLog$6.run(Test08JStackLog.java:97)

"parkThread" #16 prio=5 os_prio=31 tid=0x00007f809c000800 nid=0x6d03 waiting on condition [0x00007000091a5000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park(java.base/Native Method)
	at java.util.concurrent.locks.LockSupport.park(java.base/LockSupport.java:323)
	at com.hx.test07.Test08JStackLog$5.run(Test08JStackLog.java:88)

"parkThreadLockObj" #15 prio=5 os_prio=31 tid=0x00007f809a8b9800 nid=0x6c03 waiting on condition [0x00007000090a2000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park(java.base/Native Method)
	- parking to wait for  <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)
	at java.util.concurrent.locks.LockSupport.park(java.base/LockSupport.java:194)
	at com.hx.test07.Test08JStackLog$4.run(Test08JStackLog.java:81)

"waitThreadAcquired" #12 prio=5 os_prio=31 tid=0x00007f809a8b8800 nid=0x6903 in Object.wait() [0x0000700008d99000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(java.base/Native Method)
	- waiting on <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)
	at java.lang.Object.wait(java.base/Object.java:516)
	at com.hx.test07.Test08JStackLog$1.run(Test08JStackLog.java:41)
	- waiting to re-lock in wait() <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)

"waitThreadInQueue" #14 prio=5 os_prio=31 tid=0x00007f8099025800 nid=0x6b03 waiting for monitor entry [0x0000700008f9f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.hx.test07.Test08JStackLog$3.run(Test08JStackLog.java:69)
	- waiting to lock <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)

"sleepThread" #13 prio=5 os_prio=31 tid=0x00007f8099850800 nid=0x9903 waiting on condition [0x0000700008e9c000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(java.base/Native Method)
	at com.hx.test07.Test08JStackLog$2.run(Test08JStackLog.java:55)
	- locked <0x00000007bfbc2b80> (a com.hx.test07.Test08JStackLog)
	- locked <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)

然后我们再来看一下 这两个对象的信息, 0x00000007bfbc2af8 是 lock 对象, 0x00000007bfbc2b80 是 lock02 对象 

com.hx.test07.Test08JStackLog 
0x00000007bfbc2af8 - klass: 'com/hx/test07/Test08JStackLog'
 - ---- fields (total size 5 words):
 - 'f01' 'I' @12  0
 - 'f02' 'I' @16  0
 - 'f03' 'I' @20  0
 - 'f04' 'I' @24  0
 - 'f05' 'I' @28  0
 - private 'identStr' 'Ljava/lang/String;' @32  "lock"0x00000007bfbc2b20 (f7f78564 0)
com.hx.test07.Test08JStackLog 
0x00000007bfbc2b80 - klass: 'com/hx/test07/Test08JStackLog'
 - ---- fields (total size 5 words):
 - 'f01' 'I' @12  0
 - 'f02' 'I' @16  0
 - 'f03' 'I' @20  0
 - 'f04' 'I' @24  0
 - 'f05' 'I' @28  0
 - private 'identStr' 'Ljava/lang/String;' @32  "lock02"0x00000007bfbc2ba8 (f7f78575 0)

再来看一下 Thread 打印栈帧信息的相关代码 

打印锁的相关信息 代码如下 

runnableThread 打印出了 栈帧信息, 没有锁的相关信息 

parkThread 打印出了 栈帧信息, 没有锁的相关信息 

parkThreadLockObj 的当前栈帧, 存在 currentParkBlocker, 该对象是 lock, 其他的栈帧没有锁的相关信息 

waitThreadAcquired 的当前栈帧, 是 lock.wait, 记录了当前栈帧, 以及 wait on 哪一个对象, 父级栈帧, 获取了 lock 的锁, 但是 wait 释放了, wait 结束之后还需要 重新获取 lock 的锁, 标记的是 "waiting to re-lock in wait() <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)" 

waitThreadInQueue 的当前栈帧 是在等待获取 lock 的锁, 因为 lock 的锁被 sleepThread 获取了, 所以标记的是 "waiting to lock <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)"

sleepThread 的当前栈帧调用是 Thread.sleep 方法, 父级栈帧是线程的 run 方法, 并且获取了 lock, lock02 的锁, 因此 标记的是 "locked <0x00000007bfbc2b80> (a com.hx.test07.Test08JStackLog)", "locked <0x00000007bfbc2af8> (a com.hx.test07.Test08JStackLog)"

完 

参考

dump 中 waiting on condition、parking to wait for 应该怎么理解

为什么jstack dump 出来的线程的线程为什么都是000结尾的。

以上是关于37 jstack 的输出结果分析的主要内容,如果未能解决你的问题,请参考以下文章

java进程分析

循环神经网络的原理分析

长度转换

Jstack 命令分析

长度转换

java中虚拟机命令:jstack使用方法