1. 概述
  1. jstack 相关内容
  1. 背景
  1. 之前看了 jvm 相关 命令行工具
  1. jinfo
  2. jstat
  3. jmap
  4. jhat
  1. 它们的方向
  1. jvm 启动参数
  2. 内存资源
  1. gc 统计
  2. 堆栈快照
  3. 堆栈分析
  1. 堆栈? 不是只有堆吗?
  1. 是哈, 那栈呢?
  1. 环境
  1. OS
  1. win10
  1. Java
  1. 1.8.0_201
  1. demo
  1. Spring Boot
  1. 2.1.3
  1. shell
  1. win10 cmd
  1. 准备
  1. 一个 java 程序
  1. 我用的是基于 spring-boot 的 webmvc 程序
  1. 一个 controller 的 hello world
  1. jps
  1. 获取 java 程序 pid
  1. 最好有点 jvm 的知识
  1. 本人水平不咋样, 基本就是门槛边爬行的那种

1. jstack

  1. 概述
  1. jstack 简介
  1. jstack
  1. jvm 栈快照工具
  1. jvm 线程活跃的地方
  1. 栈的内容
  1. 以线程为单位分割
  2. 每个线程都有自己的东西
  1. 各种寄存器, 存储线程专属信息
  2. 方法栈
  1. 每个线程, 在工作中, 会有自己一系列的方法调用
  2. 这些调用, 就以 栈 的形式, 在内存中存储
  1. 分类 - 这个不细说
  1. java 栈
  1. 存储 java 方法信息
  1. 本地方法栈
  1. 存储 本地方法 的信息
  1. 比如被 java 调用的 c 语言
  1. 两者关系
  1. 老实说, 我是不清楚的...

2. 命令

  1. 命令
> jstack <pid>
  1. 结果
  1. 这个结果有点复杂, 我慢慢说

3. 结果

  1. 概述
  1. 简单讲解 jstack 的结果
  1. 结果
  1. 命令执行时, jvm 栈内的信息
  1. 主要是 方法调用 信息

segment 1 - jvm 信息

  1. 片段
2020-04-11 19:20:35
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode):
  1. 内容
  1. 2020-04-11 19:20:35
  1. jstack 命令执行时间
  1. Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode):
  1. 64-Bit
  1. 64 位系统
  1. Server VM
  1. jvm 服务器模式
  1. 25.181-b13
  1. jvm 的 build 号
  1. mixed mode
  1. HotSpot 虚拟机的默认模式
  1. 需要后续追加

segment 2 - JNI global references

  1. 片段
# 这个位于 输出日志的 最下方
JNI global references: 1041
  1. 解释
  1. JNI global references: 1041
  1. JNI - Java Native Interface
  1. Java 的本地接口
  2. 负责调用与 其他语言交互
  1. global references
  1. JNI reference
  1. Local reference
  1. 本线程 native method 中的变量
  2. 返回 java 后自动释放
  1. Global Reference
  1. 多个线程, 多个方法中使用
  2. 需要手动创建, 释放
  1. Weak Global Reference
  1. 和 Global Reference 基本一致
  2. 不过有可能会被 GC
  1. 1041
  1. 目前有 1041 个 Global Reference

segment 3: VM Periodic Task Thread 线程片段

  1. 片段
"VM Periodic Task Thread" os_prio=2 tid=0x000000003c4c5800 nid=0x5110 waiting on condition
  1. 解释
  1. "VM Periodic Task Thread"
  1. 线程名称
  1. 这个是 HotSpot 的监控进程
  2. 通过执行 周期性任务, 来获取 jvm 的各种信息
  1. os_prio=2
  1. 系统进程优先级
  1. 这个和 操作系统 有关系
  2. 后面会讲到 java 线程优先级...
  1. tid=0x000000003c4c5800
  1. java 线程id
  1. 线程在 jvm 中的 id
  1. nid=0x5110
  1. 原生系统线程 id
  1. 每个 java 线程, 都有一个对应 原生系统线程id
  1. waiting on condition
  1. 表示线程正处于 等待状态
  1. 具体条件没有说明

segment 4: GC 线程片段

  1. 片段
# 这样类似的片段, 一共有 9 个
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000031bb000 nid=0x1c54 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000031bd000 nid=0x3718 runnable 

...
  1. 解释
  1. "GC task thread#0 (ParallelGC)"
  1. 线程名称
  1. GC 线程
  2. 编号为0
  3. 使用的是 ParallelGC
  1. os_prio=0
  1. 系统进程优先级
  1. tid=0x00000000031bb000
  1. java 线程id
  1. nid=0x1c54
  1. 原生系统线程 id
  1. runnable
  1. 线程状态
  1. 这个暂时不在这里讲

segment 5: 普通线程片段

  1. 片段
"http-nio-8080-ClientPoller-1" #45 daemon prio=5 os_prio=0 tid=0x000000003e78e800 nid=0x574 runnable [0x0000000040d8f000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method)
at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:296)
at sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(WindowsSelectorImpl.java:278)
at sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:159)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000006768fe120> (a sun.nio.ch.Util$3)
- locked <0x00000006768fe110> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000006768fdfc0> (a sun.nio.ch.WindowsSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:743)
at java.lang.Thread.run(Thread.java:748)
  1. 解释
  1. "http-nio-8080-ClientPoller-1"
  1. 线程名称
  1. #45
  1. 这个我找了好久, 也不知道叫啥
  1. 也不知道为啥有的线程有, 有的线程没有
  2. 甚至连 大小 规律, 都没有搞清楚
  1. daemon
  1. 守护线程
  1. 当前线程, 是一个守护线程
  1. prio=5
  2. os_prio=0
  3. tid=0x000000003e78e800
  4. nid=0x574
  5. runnable
  1. 可执行状态
  1. [0x0000000040d8f000]
  1. 线程的 栈 起始地址
  2. 起始地址为 [0x0000000000000000]
  1. 这些通常是 jvm 的进程
  2. 它们需要与 操作系统打交道, 所以栈的起点在 本地方法栈
  3. 当然并非所有的 jvm 进程, 都是以 [0x0000000000000000] 为起始
  1. java.lang.Thread.State: RUNNABLE
  1. 线程状态...
  1. 下面的 堆栈信息
  1. 该线程正在执行的方法调用链
  2. 新的在上上面, 旧的在下面

3. 其他

  1. 命令行选项 -l
  1. 作用
  1. 增加内容, 线程的锁情况
  1. 副作用
  1. 会延长打印的时间
  1. 锁相关的内容, 后续再讲

ps

  1. ref
  1. jstack
  1. 官方文档
  2. 内容有些单薄
  1. JVM实用参数(一)JVM类型以及编译器模式
  1. 翻译的还行
  2. 2012 年的老文章...
  3. mix mode
  1. JNI学习三(Local references & Global references 以及JNI内存泄露)
  1. JNI 的讲解
  1. 这块我暂时不管了
  1. 4.5 jstack
  1. 讲得很清楚
  1. jstack 的 dump 信息
  2. java 线程状态
  3. 锁 相关
  1. JVM故障分析及性能优化系列之二:jstack生成的Thread Dump日志结构解析
  1. 写的很不错
  1. 对内容进行了科学的拆分
  2. 而且根据 线程所属组件, 明确分类
  3. 而且还是一个系列...
  4. 后头好好看下
  1. 三个实例演示 Java Thread Dump 日志分析
  1. 值得参考
  1. 虚拟机stack全分析
  1. 值得参考
  1. Java命令学习系列(二)——Jstack
  1. 问题们
  1. mix mode
  2. 线程状态
  1. 线程状态
  2. 状态转换
  1. 通过 jstack 分析与诊断 死锁问题
  1. 锁的原理
  2. 理解 线程状态
  3. 定位死锁线程
  1. 后续
  1. 可视化工具

尽量尝试解释清楚; 自己校对能力有限, 如果有错误欢迎指出