JVM篇: 监控及诊断工具命令行

2023年 7月 14日 45.5k 0

概述

性能诊断是软件工程师在日常工作中需要经常面对和解决的问题,在用户体验至上的今天,解决好应用的性能问题能带来非常大的收益。

Java 作为最流行的编程语言之一,其应用性能诊断一直受到业界广泛关注。可能造成 Java 应用出现性能问题的因素非常多,例如线程控制、磁盘读写、数据库访问、网络 I/O、垃圾收集等。想要定位这些问题,一款优秀的性能诊断工具必不可少。

体会 1:使用数据说明问题,使用知识分析问题,使用工具处理问题。

体会 2:无监控、不调优。

简单命令行工具

在我们刚接触 java 学习的时候,大家肯定最先了解的两个命令就是 javacjava,那么除此之外,还有没有其他的命令可以供我们使用呢?

我们进入到安装 jdk 的 bin 目录,发现还有一系列辅助工具。这些辅助工具用来获取目标 JVM 不同方面、不同层次的信息,帮助开发人员很好地解决 Java 应用程序的一些疑难杂症。

image-20220131152127843

官方源码地址:http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/jdk.jcmd/share/classes/sun/tools

jps:查看正在运行的 Java 进程

jps(Java Process Status):显示指定系统内所有的 HotSpot 虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程。

说明:对于本地虚拟机进程来说,进程的本地虚拟机 ID 与操作系统的进程 ID 是一致的,是唯一的。

基本使用语法为:jps [options] [hostid]

代码示例

public class ScannerTest {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String info = scanner.next();
    }
}

运行后,在命令行输入 jps 查看进程:

image-20220131153051380

我们还可以通过追加参数,来打印额外的信息。

options 参数

  • -q:仅仅显示 LVMID(local virtual machine id),即本地虚拟机唯一 id。不显示主类的名称等
  • -l:输出应用程序主类的全类名或如果进程执行的是 jar 包,则输出 jar 完整路径
  • -m:输出虚拟机进程启动时传递给主类 main() 的参数
  • -v:列出虚拟机进程启动时的 JVM 参数。比如:-Xms20m -Xmx50m 是启动程序指定的 jvm 参数

说明:以上参数可以综合使用。

如图:

image-20220131153248445

补充:如果某 Java 进程关闭了默认开启的 UsePerfData 参数(即使用参数 -XX:-UsePerfData),那么 jps 命令(以及下面介绍的 jstat)将无法探知该 Java 进程。

hostid 参数

RMI 注册表中注册的主机名。如果想要远程监控主机上的 java 程序,需要安装 jstatd。

对于具有更严格的安全实践的网络场所而言,可能使用一个自定义的策略文件来显示对特定的可信主机或网络的访问,尽管这种技术容易受到 IP 地址欺诈攻击。

如果安全问题无法使用一个定制的策略文件来处理,那么最安全的操作是不运行 jstatd 服务器,而是在本地使用 jstat 和 jps 工具。

jstat:查看 JVM 统计信息

官方文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。在没有 GUI 图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。常用于检测垃圾回收问题以及内存泄漏问题。

基本使用语法为:jstat - [-t] [-h] [ []]

查看命令相关参数:jstat-hjstat-help

其中 vmid 是进程 id 号,也就是 jps 之后看到的前面的号码,如下:

image-20220131153629853

option参数

选项 option 可以由以下值构成:

类装载相关的:

  • -class:显示 ClassLoader 的相关信息:类的装载、卸载数量、总空间、类装载所消耗的时间等

垃圾回收相关的:

  • -gc:显示与 GC 相关的堆信息。包括 Eden 区、两个 Survivor 区、老年代、永久代等的容量、已用空间、GC 时间合计等信息
  • -gccapacity:显示内容与 -gc 基本相同,但输出主要关注 Java 堆各个区域使用到的最大、最小空间
  • -gcutil:显示内容与 -gc 基本相同,但输出主要关注已使用空间占总空间的百分比
  • -gccause:与 -gcutil 功能一样,但是会额外输出导致最后一次或当前正在发生的 GC 产生的原因
  • -gcnew:显示新生代 GC 状况
  • -gcnewcapacity:显示内容与 -gcnew 基本相同,输出主要关注使用到的最大、最小空间
  • -geold:显示老年代 GC 状况
  • -gcoldcapacity:显示内容与 -gcold 基本相同,输出主要关注使用到的最大、最小空间
  • -gcpermcapacity:显示永久代使用到的最大、最小空间

JIT 相关的:

  • -compiler:显示 JIT 编译器编译过的方法、耗时等信息
  • -printcompilation:输出已经被 JIT 编译的方法

jstat -class

image-20220131153919947

jstat -compiler

显示 JIT 编译器编译过的方法、耗时等信息。

image-20220131154943898

jstat -printcompilation

输出已经被 JIT 编译的方法。

image-20220131155122971

jstat -gc

显示与 GC 相关的堆信息。包括 Eden 区、两个 Survivor 区、老年代、永久代等的容量、已用空间、GC 时间合计等信息。

执行代码:

public class GCTest {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
​
        for (int i = 0; i < 1000; i++) {
            byte[] arr = new byte[1024 * 100];//100KB
            list.add(arr);
            try {
                Thread.sleep(120);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

JVM 参数:

-Xms60m -Xmx60m -XX:SurvivorRatio=8

运行后利用命令查询:

image-20220131160826978

表头 含义(字节)
S0C 幸存者 0 区的大小
S1C 幸存者 1 区的大小
S0U 幸存者 0 区已使用的大小
S1U 幸存者 1 区已使用的大小
EC Eden 区的大小
EU Eden 区已使用的大小
OC 老年代的大小
OU 老年代已使用的大小
MC 元空间的大小
MU 元空间已使用的大小
CCSC 压缩类空间的大小
CCSU 压缩类空间已使用的大小
YGC 从应用程序启动到采样时 Young GC 的次数
YGCT 从应用程序启动到采样时 Young GC 消耗时间(秒)
FGC 从应用程序启动到采样时 Full GC 的次数
FGCT 从应用程序启动到采样时的 Full GC 的消耗时间(秒)
GCT 从应用程序启动到采样时 GC 的总时间

后面的参数代表 1000 毫秒打印一次,一个打印 10 次。

jstat -gccapacity

显示内容与 -gc 基本相同,但输出主要关注 Java 堆各个区域使用到的最大、最小空间。

image-20220131160931520

jstat -gcutil

显示内容与 -gc 基本相同,但输出主要关注已使用空间占总空间的百分比。

image-20220131161054138

表头 含义(字节)
SO Survivor 0 区空间百分比
S1 Survivor 1 区空间百分比
E Eden 区空间百分比
O Old 区空间百分比
N 方法区空间百分比
CCS 压缩空间百分比
YGC 从应用程序启动到采样时 Young GC 的次数
YGCT 从应用程序启动到采样时 Young GC 消耗时间(秒)
FGC 从应用程序启动到采样时 Full GC 的次数
FGCT 从应用程序启动到采样时的 Full GC 的消耗时间(秒)
GCT 从应用程序启动到采样时 GC 的总时间

jstat -gccause

-gcutil 功能一样,但是会额外输出导致最后一次或当前正在发生的 GC 产生的原因。

image-20220131161322060

jstat -gcnew

显示新生代 GC 状况。

image-20220131161525208

jstat -gcnewcapacity

显示内容与 -gcnew 基本相同,输出主要关注使用到的最大、最小空间。

image-20220131161618811

jstat -gcold

显示老年代 GC 状况。

image-20220131161659710

jstat -gcoldcapacity

显示内容与 -gcold 基本相同,输出主要关注使用到的最大、最小空间。

image-20220131161741659

其他参数

下面的参数都是配合 option 参数后面使用。

基本使用语法为:jstat - [-t] [-h] [ []]

  • interval 参数:用于指定输出统计数据的周期,单位为毫秒。即:查询间隔

  • count 参数:用于指定查询的总次数

  • -t 参数:可以在输出信息前加上一个 Timestamp 列,显示程序的运行时间。单位:秒

    我们可以比较 Java 进程的启动时间以及总 GC 时间(GCT 列),或者两次测量的间隔时间以及总 GC 时间的增量,来得出 GC 时间占运行时间的比例。

    如果该比例超过 20%,则说明目前堆的压力较大;如果该比例超过 90%,则说明堆里几乎没有可用空间,随时都可能抛出 OOM 异常。

  • -h 参数:可以在周期性数据输出时,输出多少行数据后输出一个表头信息

image-20220131154811037

jstat -t

可以在输出信息前加上一个 Timestamp 列,显示程序的运行时间。单位:秒。

image-20220131161938786

jstat -t -h

可以在周期性数据输出时,输出多少行数据后输出一个表头信息。

image-20220131162141993

其他功能

jstat 还可以用来判断是否出现内存泄漏:

  • 第 1 步:在长时间运行的 Java 程序中,我们可以运行 jstat 命令连续获取多行性能数据,并取这几行数据中 OU 列(即已占用的老年代内存)的最小值
  • 第 2 步:然后,我们每隔一段较长的时间重复一次上述操作,来获得多组 OU 最小值。如果这些值呈上涨趋势,则说明该 Java 程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏

jinfo:实时查看和修改 JVM 配置参数

jinfo(Configuration Info for Java):查看虚拟机配置参数信息,也可用于调整虚拟机的配置参数。在很多情况卡,Java 应用程序不会指定所有的 Java 虚拟机参数。而此时,开发人员可能不知道某一个具体的 Java 虚拟机参数的默认值。在这种情况下,可能需要通过查找文档获取某个参数的默认值。这个查找过程可能是非常艰难的。但有了 jinfo 工具,开发人员可以很方便地找到 Java 虚拟机参数的当前值。

jinfo 不仅可以查看运行时某一个 Java 虚拟机参数的实际取值,甚至可以在运行时修改部分参数,并使之立即生效。

但是,并非所有参数都支持动态修改。参数只有被标记为 manageable 的 flag 可以被实时修改。其实,这个修改能力是极其有限的。

基本使用语法为:jinfo [options] pid

说明:java 进程 ID 必须要加上。

选项 选项说明
no option 输出全部的参数和系统属性
-flag name 输出对应名称的参数
-flag [+-]name 开启或者关闭对应名称的参数 只有被标记为 manageable 的参数才可以被动态修改
-flag name=value 设定对应名称的参数
-flags 输出全部的参数
-sysprops 输出系统属性

参数查看

jinfo -sysprops

> jinfo -sysprops
jboss.modules.system.pkgs = com.intellij.rt
java.vendor = Oracle Corporation
sun.java.launcher = SUN_STANDARD
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
catalina.useNaming = true
os.name = Windows 10
...

jinfo -flags

C:\Users\24560>jps
13968 GCTest
22016 Launcher
8912
17740 Jps
​
C:\Users\24560>jinfo -flags 13968
​
# 输出结果如下:
Attaching to process ID 13968, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.231-b11
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=62914560 -XX:MaxHeapSize=62914560 -XX:MaxNewSize=20971520 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=20971520 -XX:OldSize=41943040 -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -Xms60m -Xmx60m -XX:SurvivorRatio=8 -javaagent:F:\Programming area\Ideal\IntelliJ IDEA 2020.3\lib\idea_rt.jar=55919:F:\Programming area\Ideal\IntelliJ IDEA 2020.3\bin -Dfile.encoding=UTF-8

jinfo -flag name

查看当前的 Java 程序是否使用了指定的参数。

> jinfo -flag UseParallelGC 13968
-XX:+UseParallelGC
​
> jinfo -flag UseG1GC 13968
-XX:-UseG1GC

参数修改

jinfo -flag [+-]name

开启或者关闭对应名称的参数 只有被标记为 manageable 的参数才可以被动态修改。

> jinfo -flag +PrintGCDetails 13968
> jinfo -flag PrintGCDetails 13968
-XX:+PrintGCDetails
​
> jinfo -flag -PrintGCDetails 13968
> jinfo -flag PrintGCDetails 13968
-XX:-PrintGCDetails

参数拓展

java -XX:+PrintFlagsInitial

查看所有 JVM 参数启动的初始值。

[Global flags]
     intx ActiveProcessorCount                      = -1                                  {product}
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10                                  {product}
    uintx AdaptiveSizePausePolicy                   = 0                                   {product}
...

java -XX:+PrintFlagsFinal

查看所有 JVM 参数的最终值。

java -XX:+PrintFlagsFinal -version | grep manageable:可以查看被标记为 manageable 的参数。

manageable 参数就是在 Java 程序启动后还能重新设置的参数,如 GC 就不能在启动程序后再重新修改,所以不是 manageable 参数。

[Global flags]
     intx ActiveProcessorCount                      = -1                                  {product}
...
     intx CICompilerCount                          := 4                                   {product}
    uintx InitialHeapSize                          := 333447168                           {product}
    uintx MaxHeapSize                              := 1029701632                          {product}
    uintx MaxNewSize                               := 1774714880                          {product}

java -XX:+PrintCommandLineFlags

查看哪些已经被用户或者 JVM 设置过的详细的 XX 参数的名称和值。

-XX:InitialHeapSize=332790016 -XX:MaxHeapSize=5324640256 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

jmap:导出内存映像文件&内存使用情况

官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jmap.html

jmap(JVM Memory Map):作用一方面是获取 dump 文件(堆转储快照文件,二进制文件),它还可以获取目标 Java 进程的内存相关信息,包括 Java 堆各区域的使用情况、堆中对象的统计信息、类加载信息等。开发人员可以在控制台中输入命令 jmap -help 查阅 jmap 工具的具体使用方式和一些标准选项配置。

基本语法

基本使用语法为:

  • jmap [option]
  • jmap [option]
    jmap -dump:live,format=b,file=

    使用如图:

    image-20220131172515141

    在 D 盘生成了 4 个文件,其中 4.hprof 用了第二个命令生成。

    image-20220131173748601

    文件的大小依次递增,因为运行越久,里面的对象越多,占用的空间越大。

    建议使用 jmap -dump:live,format=b,file= 命令生成 dump 文件,因为只需要获取存活的对象,没必要把被回收或者死亡的对象 dump 到文件里,导致文件太大。

    自动方式

    当程序发生 OOM 退出系统时,一些瞬时信息都随着程序的终止而消失,而重现 OOM 问题往往比较困难或者耗时。此时若能在 OOM 时,自动导出 dump 文件就显得非常迫切。

    这里介绍一种比较常用的取得堆快照文件的方法,即使用:

    -XX:HeapDumpOnOutOfMemoryError:在程序发生 OOM 时,导出应用程序的当前堆快照。

    -XX:HeapDumpPath=:可以指定堆快照的保存位置。

    代码示例如下:

    public class GCTest {
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
    ​
            for (int i = 0; i < 1000; i++) {
                byte[] arr = new byte[1024 * 100];//100KB
                list.add(arr);
                try {
                    Thread.sleep(60);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    设置 JVM 参数:

    -Xms60m -Xmx60m -XX:+HeapDumpOnOutOfMemoryError
    -XX:HeapDumpPath=D:\5.hprof
    

    运行代码后,当发生 OOM 异常,则立马在 D 盘生成 5.hprof 文件。

    image-20220131173702078

    显示堆内存相关信息

    两个常用命令:

    • jmap -heap pid
    • jmap -histo pid

    命令行示例:

    jps
    17744 Launcher
    1904 GCTest
    8912
    15316 Jps
    ​
    jmap -heap 3540 > a.txt
    ​
    jmap -histo 1904 > b.txt
    

    image-20220131211705430

    两个命令将信息分别写到了 a.txt、b.txt 文件。

    a.txt 内容为:

    Attaching to process ID 1904, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.231-b11
    ​
    using thread-local object allocation.
    Parallel GC with 10 thread(s)
    ​
    Heap Configuration:
       MinHeapFreeRatio         = 0
       MaxHeapFreeRatio         = 100
       MaxHeapSize              = 4255121408 (4058.0MB)
       NewSize                  = 88604672 (84.5MB)
       MaxNewSize               = 1418199040 (1352.5MB)
       OldSize                  = 177733632 (169.5MB)
       NewRatio                 = 2
       SurvivorRatio            = 8
       MetaspaceSize            = 21807104 (20.796875MB)
       CompressedClassSpaceSize = 1073741824 (1024.0MB)
       MaxMetaspaceSize         = 17592186044415 MB
       G1HeapRegionSize         = 0 (0.0MB)
    ​
    Heap Usage:
    PS Young Generation
    Eden Space:
       capacity = 66584576 (63.5MB)
       used     = 31136256 (29.69384765625MB)
       free     = 35448320 (33.80615234375MB)
       46.761964812992126% used
    From Space:
       capacity = 11010048 (10.5MB)
       used     = 0 (0.0MB)
       free     = 11010048 (10.5MB)
       0.0% used
    To Space:
       capacity = 11010048 (10.5MB)
       used     = 0 (0.0MB)
       free     = 11010048 (10.5MB)
       0.0% used
    PS Old Generation
       capacity = 177733632 (169.5MB)
       used     = 0 (0.0MB)
       free     = 177733632 (169.5MB)
       0.0% used
    ​
    3163 interned Strings occupying 259640 bytes.
    

    b.txt 内容:

     num     #instances         #bytes  class name
    ----------------------------------------------
       1:          1610       44293784  [B
       2:           659        2906760  [I
       3:          7774         906192  [C
       4:          5933         142392  java.lang.String
       5:           691          79112  java.lang.Class
       6:          1305          67680  [Ljava.lang.Object;
       7:           791          31640  java.util.TreeMap$Entry
       8:           628          25120  java.util.LinkedHashMap$Entry
       9:           456          22168  [Ljava.lang.String;
      10:           364          11648  java.util.HashMap$Node
      11:            37          11504  [Ljava.util.HashMap$Node;
      12:           152          10944  java.lang.reflect.Field
      13:           438          10512  java.lang.StringBuilder
      14:           242           7744  java.util.Hashtable$Entry
      15:           233           7456  java.io.File
      16:           101           6464  java.net.URL
      17:           241           5784  java.lang.StringBuffer
      18:           125           5000  java.lang.ref.SoftReference
      19:           258           4128  java.lang.Integer
      20:           117           3744  java.util.concurrent.ConcurrentHashMap$Node
      21:            25           3648  [Ljava.util.Hashtable$Entry;
      22:            75           3600  java.nio.HeapCharBuffer
      23:            74           3552  java.nio.HeapByteBuffer
      24:            42           3360  [S
      25:             8           3008  java.lang.Thread
      26:             5           2568  [J
      27:            20           2496  [Ljava.util.concurrent.ConcurrentHashMap$Node;
      28:            44           2464  sun.misc.URLClassPath$JarLoader
      29:             2           2384  [[Ljava.lang.Object;
      30:            89           2136  java.net.Parts
      31:             2           2080  [[C
      32:            26           2080  java.lang.reflect.Constructor
      33:            39           1872  sun.util.locale.LocaleObjectCache$CacheEntry
      34:            43           1720  java.lang.ref.Finalizer
      35:            34           1632  java.util.HashMap
      36:             1           1568  [[B
      37:            37           1480  java.io.ObjectStreamField
      38:            26           1456  java.lang.Class$ReflectionData
      39:            91           1456  java.lang.Object
      40:            20           1280  java.util.concurrent.ConcurrentHashMap
      41:            15           1200  [Ljava.util.WeakHashMap$Entry;
      42:            45           1080  sun.misc.URLClassPath$3
      43:             2           1064  [Ljava.lang.invoke.MethodHandle;
      44:            11           1056  java.util.jar.JarFile$JarFileEntry
      45:             1           1040  [Ljava.lang.Integer;
      46:            41            984  java.io.ExpiringCache$Entry
      47:            11            880  java.util.zip.ZipEntry
      48:            22            880  sun.util.locale.BaseLocale$Key
      49:            47            840  [Ljava.lang.Class;
      50:            15            840  sun.nio.cs.UTF_8$Encoder
      51:            34            816  sun.security.action.GetPropertyAction
      52:            12            768  java.util.jar.JarFile
      53:            12            752  [Ljava.lang.reflect.Field;
      54:            15            720  java.util.WeakHashMap
      55:            22            704  java.lang.ref.ReferenceQueue
      56:            17            680  java.util.WeakHashMap$Entry
      57:            12            672  java.util.zip.ZipFile$ZipFileInputStream
      58:            19            608  java.util.Locale
      59:            19            608  sun.util.locale.BaseLocale
      60:            14            560  sun.nio.cs.UTF_8$Decoder
      61:            22            528  java.util.Locale$LocaleKey
      62:            13            520  java.security.AccessControlContext
      63:            21            504  java.util.jar.Attributes$Name
      64:            18            432  sun.misc.MetaIndex
      65:            10            400  java.io.FileDescriptor
      66:            13            392  [Ljava.io.ObjectStreamField;
      67:             1            384  com.intellij.rt.execution.application.AppMainV2$1
      68:             1            384  java.lang.ref.Finalizer$FinalizerThread
      69:            24            384  java.lang.ref.ReferenceQueue$Lock
      70:             6            384  java.nio.DirectByteBuffer
      71:            16            384  java.util.ArrayList
      72:            12            384  java.util.zip.ZipCoder
      73:             1            376  java.lang.ref.Reference$ReferenceHandler
      74:             4            352  java.lang.reflect.Method
      75:             6            336  java.nio.DirectLongBufferU
      76:             7            336  java.util.Hashtable
      77:             7            336  java.util.Hashtable$Enumerator
      78:             6            336  java.util.LinkedHashMap
      79:            14            336  sun.misc.FileURLMapper
      80:             6            336  sun.nio.cs.ext.DoubleByte$Decoder
      81:            10            320  java.lang.OutOfMemoryError
      82:            10            320  java.util.Vector
      83:             3            312  [D
      84:            13            312  [Ljava.lang.reflect.Constructor;
      85:            13            312  java.lang.Class$1
      86:            13            312  sun.reflect.NativeConstructorAccessorImpl
      87:            12            288  java.util.ArrayDeque
      88:             6            288  java.util.Properties
      89:             3            280  [[Ljava.lang.String;
      90:             5            280  java.util.ResourceBundle$CacheKey
      91:             5            280  sun.util.calendar.ZoneInfo
      92:             3            240  [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;
      93:             3            232  [Ljava.net.URL;
      94:             7            224  java.lang.ThreadLocal$ThreadLocalMap$Entry
      95:             7            224  java.security.CodeSource
      96:            14            224  sun.misc.URLClassPath$JarLoader$1
      97:             9            216  java.util.LinkedList$Node
      98:             2            208  sun.net.www.protocol.file.FileURLConnection
      99:            13            208  sun.reflect.DelegatingConstructorAccessorImpl
     100:             5            200  java.security.ProtectionDomain
     101:             3            192  [Ljava.io.File;
     102:             4            192  java.io.BufferedReader
     103:             6            192  java.io.FileInputStream
     104:             8            192  java.net.URLClassLoader$1
     105:             4            192  java.util.TreeMap
     106:             4            192  sun.nio.cs.StreamDecoder
     107:             4            192  sun.nio.cs.StreamEncoder
     108:             3            192  sun.nio.cs.ext.DoubleByte$Encoder
     109:             2            192  sun.util.calendar.Gregorian$Date
     110:             4            160  java.io.BufferedWriter
     111:             4            160  java.lang.ClassLoader$NativeLibrary
     112:             4            160  java.lang.ClassNotFoundException
     113:             4            160  java.security.PrivilegedActionException
     114:             5            160  java.util.LinkedList
     115:             5            160  java.util.ResourceBundle$LoaderReference
     116:             5            160  sun.util.locale.provider.LocaleProviderAdapter$Type
     117:             3            144  java.util.StringTokenizer
     118:             6            144  sun.misc.PerfCounter
     119:             3            144  sun.misc.URLClassPath
     120:             6            144  sun.usagetracker.UsageTrackerClient$1
     121:             2            128  java.io.ExpiringCache$1
     122:             4            128  java.lang.StringCoding$StringDecoder
     123:             4            128  java.lang.StringCoding$StringEncoder
     124:             4            128  java.util.Stack
     125:             4            128  java.util.concurrent.ConcurrentHashMap$ForwardingNode
     126:             3            120  java.io.BufferedInputStream
     127:             1            120  java.net.SocksSocketImpl
     128:             5            120  java.util.Collections$UnmodifiableRandomAccessList
     129:             5            120  sun.misc.FloatingDecimal$PreparedASCIIToBinaryBuffer
     130:             7            112  java.lang.Class$3
     131:             2            112  java.lang.Package
     132:             2            112  java.util.zip.ZipFile$ZipFileInflaterInputStream
     133:             2            112  sun.nio.cs.ISO_8859_1$Encoder
     134:             3             96  java.io.FileOutputStream
     135:             3             96  java.io.FilePermission
     136:             4             96  java.io.OutputStreamWriter
     137:             4             96  java.lang.RuntimePermission
     138:             2             96  java.lang.ThreadGroup
     139:             3             96  java.lang.ref.WeakReference
     140:             3             96  java.util.ArrayList$Itr
     141:             6             96  java.util.HashSet
     142:             2             96  java.util.ResourceBundle$BundleReference
     143:             2             96  java.util.zip.Inflater
     144:             1             96  sun.misc.Launcher$AppClassLoader
     145:             3             96  sun.misc.URLClassPath$JarLoader$2
     146:             3             96  sun.net.spi.DefaultProxySelector$NonProxyInfo
     147:             1             88  java.net.DualStackPlainSocketImpl
     148:             1             88  sun.misc.Launcher$ExtClassLoader
     149:             5             80  [Ljava.security.Principal;
     150:             2             80  [Lsun.util.locale.provider.LocaleProviderAdapter$Type;
     151:             2             80  java.io.ExpiringCache
     152:             5             80  java.io.FileInputStream$1
     153:             5             80  java.lang.ClassLoader$3
     154:             5             80  java.lang.ThreadLocal
     155:             1             80  java.net.URI
     156:             5             80  java.security.ProtectionDomain$Key
     157:             2             80  java.util.ServiceLoader$LazyIterator
     158:             2             80  sun.misc.FloatingDecimal$BinaryToASCIIBuffer
     159:             2             80  sun.misc.URLClassPath$1
     160:             2             80  sun.misc.URLClassPath$2
     161:             2             80  sun.util.locale.LanguageTag
     162:             3             72  [Ljava.lang.reflect.Method;
     163:             3             72  java.lang.ThreadLocal$ThreadLocalMap
     164:             3             72  java.net.Proxy$Type
     165:             3             72  java.util.Arrays$ArrayList
     166:             3             72  java.util.Collections$SynchronizedSet
     167:             1             72  java.util.ResourceBundle$RBClassLoader
     168:             3             72  java.util.concurrent.atomic.AtomicLong
     169:             3             72  sun.misc.FloatingDecimal$ExceptionalBinaryToASCIIBuffer
     170:             1             72  sun.util.locale.provider.JRELocaleProviderAdapter
     171:             1             64  [F
     172:             2             64  [Ljava.lang.Thread;
     173:             2             64  java.io.DataInputStream
     174:             2             64  java.io.FileNotFoundException
     175:             2             64  java.io.PrintStream
     176:             2             64  java.lang.ClassValue$Entry
     177:             2             64  java.lang.NoSuchMethodError
     178:             2             64  java.lang.VirtualMachineError
     179:             2             64  java.lang.ref.ReferenceQueue$Null
     180:             2             64  java.security.BasicPermissionCollection
     181:             2             64  java.security.Permissions
     182:             2             64  java.util.LinkedHashMap$LinkedEntryIterator
     183:             2             64  java.util.ServiceLoader
     184:             4             64  sun.reflect.ReflectionFactory$1
     185:             2             48  [Ljava.util.Enumeration;
     186:             2             48  java.io.BufferedOutputStream
     187:             2             48  java.io.ByteArrayOutputStream
     188:             2             48  java.io.File$PathStatus
     189:             3             48  java.io.FilePermission$1
     190:             2             48  java.io.FilePermissionCollection
     191:             2             48  java.io.FileReader
     192:             2             48  java.io.InputStreamReader
     193:             2             48  java.net.InetAddress$Cache
     194:             2             48  java.net.InetAddress$Cache$Type
     195:             1             48  java.net.SocketInputStream
     196:             2             48  java.net.URLClassLoader$3
     197:             2             48  java.nio.charset.CoderResult
     198:             3             48  java.nio.charset.CodingErrorAction
     199:             2             48  java.util.Date
     200:             1             48  java.util.Properties$LineReader
     201:             2             48  java.util.ServiceLoader$1
     202:             2             48  java.util.zip.ZStreamRef
     203:             2             48  sun.instrument.InstrumentationImpl$1
     204:             2             48  sun.misc.CompoundEnumeration
     205:             2             48  sun.misc.NativeSignalHandler
     206:             2             48  sun.misc.Signal
     207:             2             48  sun.net.www.MessageHeader
     208:             3             48  sun.net.www.ParseUtil
     209:             3             48  sun.net.www.protocol.jar.Handler
     210:             2             48  sun.nio.cs.Surrogate$Parser
     211:             1             48  sun.nio.cs.US_ASCII$Decoder
     212:             3             48  sun.reflect.ReflectionFactory$GetReflectionFactoryAction
     213:             1             48  sun.util.locale.provider.LocaleResources$ResourceReference
     214:             1             48  sun.util.resources.TimeZoneNames
     215:             1             48  sun.util.resources.en.TimeZoneNames_en
     216:             1             40  java.util.ResourceBundle$1
     217:             1             40  sun.nio.cs.StandardCharsets$Aliases
     218:             1             40  sun.nio.cs.StandardCharsets$Cache
     219:             1             40  sun.nio.cs.StandardCharsets$Classes
     220:             1             40  sun.nio.cs.ext.ExtendedCharsets
     221:             1             32  [Ljava.lang.OutOfMemoryError;
     222:             2             32  [Ljava.lang.StackTraceElement;
     223:             1             32  [Ljava.lang.ThreadGroup;
     224:             1             32  [Ljava.net.Proxy$Type;
     225:             1             32  java.io.ByteArrayInputStream
     226:             1             32  java.io.WinNTFileSystem
     227:             1             32  java.lang.ArithmeticException
     228:             2             32  java.lang.Boolean
     229:             2             32  java.lang.ClassLoader$2
     230:             1             32  java.lang.InternalError
     231:             1             32  java.lang.NullPointerException
     232:             1             32  java.net.InetAddress$InetAddressHolder
     233:             1             32  java.net.Socket
     234:             1             32  java.net.URI$Parser
     235:             2             32  java.net.URLClassLoader$3$1
     236:             2             32  java.nio.ByteOrder
     237:             2             32  java.util.Hashtable$KeySet
     238:             2             32  java.util.LinkedHashMap$LinkedEntrySet
     239:             2             32  java.util.LinkedHashMap$LinkedKeySet
     240:             2             32  java.util.concurrent.atomic.AtomicInteger
     241:             1             32  java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl
     242:             1             32  java.util.jar.Manifest$FastInputStream
     243:             1             32  sun.instrument.InstrumentationImpl
     244:             1             32  sun.misc.FloatingDecimal$ASCIIToBinaryBuffer
     245:             2             32  sun.misc.PostVMInitHook$1
     246:             1             32  sun.misc.URLClassPath$FileLoader$1
     247:             1             32  sun.net.spi.DefaultProxySelector$3
     248:             1             32  sun.nio.cs.StandardCharsets
     249:             2             32  sun.usagetracker.UsageTrackerClient$2
     250:             2             32  sun.usagetracker.UsageTrackerClient$3
     251:             1             32  sun.util.locale.provider.LocaleResources
     252:             1             32  sun.util.locale.provider.LocaleServiceProviderPool
     253:             1             24  [Ljava.io.File$PathStatus;
     254:             1             24  [Ljava.lang.ClassValue$Entry;
     255:             1             24  [Ljava.net.InetAddress$Cache$Type;
     256:             1             24  [Ljava.net.InetAddress;
     257:             1             24  [Ljava.security.ProtectionDomain;
     258:             1             24  [Lsun.launcher.LauncherHelper;
     259:             1             24  java.lang.Class$MethodArray
     260:             1             24  java.lang.ClassValue$Version
     261:             1             24  java.lang.invoke.MethodHandleImpl$4
     262:             1             24  java.lang.reflect.ReflectPermission
     263:             1             24  java.net.Inet4Address
     264:             1             24  java.net.Inet6AddressImpl
     265:             1             24  java.net.InetSocketAddress$InetSocketAddressHolder
     266:             1             24  java.net.Proxy
     267:             1             24  java.util.BitSet
     268:             1             24  java.util.Collections$EmptyMap
     269:             1             24  java.util.Collections$SetFromMap
     270:             1             24  java.util.Collections$UnmodifiableCollection$1
     271:             1             24  java.util.Locale$Cache
     272:             1             24  java.util.ResourceBundle$Control$CandidateListCache
     273:             1             24  java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl$1
     274:             1             24  java.util.jar.Manifest
     275:             1             24  sun.instrument.TransformerManager
     276:             1             24  sun.launcher.LauncherHelper
     277:             1             24  sun.misc.JarIndex
     278:             1             24  sun.misc.Launcher$AppClassLoader$1
     279:             1             24  sun.misc.URLClassPath$FileLoader
     280:             1             24  sun.nio.cs.ISO_8859_1
     281:             1             24  sun.nio.cs.ThreadLocalCoders$1
     282:             1             24  sun.nio.cs.ThreadLocalCoders$2
     283:             1             24  sun.nio.cs.US_ASCII
     284:             1             24  sun.nio.cs.UTF_16
     285:             1             24  sun.nio.cs.UTF_16BE
     286:             1             24  sun.nio.cs.UTF_16LE
     287:             1             24  sun.nio.cs.UTF_8
     288:             1             24  sun.nio.cs.ext.GBK
     289:             1             24  sun.reflect.NativeMethodAccessorImpl
     290:             1             24  sun.usagetracker.UsageTrackerClient$4
     291:             1             24  sun.util.locale.BaseLocale$Cache
     292:             1             24  sun.util.locale.provider.SPILocaleProviderAdapter$1
     293:             1             24  sun.util.locale.provider.TimeZoneNameProviderImpl
     294:             1             24  sun.util.resources.LocaleData$1
     295:             1             16  [Ljava.lang.Throwable;
     296:             1             16  [Ljava.security.cert.Certificate;
     297:             1             16  [Lsun.instrument.TransformerManager$TransformerInfo;
     298:             1             16  [Lsun.util.calendar.ZoneInfoFile$ZoneOffsetTransitionRule;
     299:             1             16  java.io.FileDescriptor$1
     300:             1             16  java.io.FileOutputStream$1
     301:             1             16  java.lang.CharacterDataLatin1
     302:             1             16  java.lang.ClassValue$Identity
     303:             1             16  java.lang.Compiler$1
     304:             1             16  java.lang.Runtime
     305:             1             16  java.lang.String$CaseInsensitiveComparator
     306:             1             16  java.lang.System$2
     307:             1             16  java.lang.SystemClassLoaderAction
     308:             1             16  java.lang.Terminator$1
     309:             1             16  java.lang.invoke.MemberName$Factory
     310:             1             16  java.lang.invoke.MethodHandleImpl$1
     311:             1             16  java.lang.invoke.MethodHandleImpl$2
     312:             1             16  java.lang.invoke.MethodHandleImpl$3
     313:             1             16  java.lang.invoke.MethodHandleStatics$1
     314:             1             16  java.lang.ref.Reference$1
     315:             1             16  java.lang.ref.Reference$Lock
     316:             1             16  java.lang.reflect.ReflectAccess
     317:             1             16  java.net.AbstractPlainSocketImpl$1
     318:             1             16  java.net.InetAddress$1
     319:             1             16  java.net.InetAddress$2
     320:             1             16  java.net.InetSocketAddress
     321:             1             16  java.net.PlainSocketImpl$1
     322:             1             16  java.net.Socket$2
     323:             1             16  java.net.SocksSocketImpl$3
     324:             1             16  java.net.URLClassLoader$7
     325:             1             16  java.nio.Bits$1
     326:             1             16  java.nio.charset.Charset$ExtendedProviderHolder$1
     327:             1             16  java.nio.charset.CoderResult$1
     328:             1             16  java.nio.charset.CoderResult$2
     329:             1             16  java.security.ProtectionDomain$2
     330:             1             16  java.security.ProtectionDomain$JavaSecurityAccessImpl
     331:             1             16  java.util.Collections$EmptyIterator
     332:             1             16  java.util.Collections$EmptyList
     333:             1             16  java.util.Collections$EmptySet
     334:             1             16  java.util.Hashtable$EntrySet
     335:             1             16  java.util.ResourceBundle$Control
     336:             1             16  java.util.ResourceBundle$RBClassLoader$1
     337:             1             16  java.util.TimeZone$1
     338:             1             16  java.util.WeakHashMap$KeySet
     339:             1             16  java.util.concurrent.atomic.AtomicBoolean
     340:             1             16  java.util.jar.Attributes
     341:             1             16  java.util.jar.JavaUtilJarAccessImpl
     342:             1             16  java.util.zip.ZipFile$1
     343:             1             16  sun.misc.ASCIICaseInsensitiveComparator
     344:             1             16  sun.misc.FloatingDecimal$1
     345:             1             16  sun.misc.Launcher
     346:             1             16  sun.misc.Launcher$BootClassPathHolder$1
     347:             1             16  sun.misc.Launcher$ExtClassLoader$1
     348:             1             16  sun.misc.Launcher$Factory
     349:             1             16  sun.misc.Perf
     350:             1             16  sun.misc.Perf$GetPerfAction
     351:             1             16  sun.misc.PostVMInitHook$2
     352:             1             16  sun.misc.Unsafe
     353:             1             16  sun.net.NetProperties$1
     354:             1             16  sun.net.spi.DefaultProxySelector
     355:             1             16  sun.net.spi.DefaultProxySelector$1
     356:             1             16  sun.net.www.protocol.file.Handler
     357:             1             16  sun.reflect.DelegatingMethodAccessorImpl
     358:             1             16  sun.reflect.ReflectionFactory
     359:             1             16  sun.security.action.GetBooleanAction
     360:             1             16  sun.usagetracker.UsageTrackerClient
     361:             1             16  sun.util.calendar.Gregorian
     362:             1             16  sun.util.calendar.ZoneInfoFile$1
     363:             1             16  sun.util.calendar.ZoneInfoFile$Checksum
     364:             1             16  sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider
     365:             1             16  sun.util.locale.provider.JRELocaleProviderAdapter$1
     366:             1             16  sun.util.locale.provider.SPILocaleProviderAdapter
     367:             1             16  sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter
     368:             1             16  sun.util.resources.LocaleData
     369:             1             16  sun.util.resources.LocaleData$LocaleDataResourceBundleControl
    Total         24100       48649392
    

    其他作用

    jmap -permstat pid

    查看系统的 ClassLoader 信息。

    jmap -finalizerinfo pid

    查看堆积在 finalizer 队列中的对象。

    小结

    由于 jmap 将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap 需要借助安全点机制,让所有线程停留在不改变堆中数据的状态。也就是说,由 jmap 导出的堆快照必定是安全点位置的。这可能导致基于该堆快照的分析结果存在偏差。

    举个例子,假设在编译生成的机器码中,某些对象的生命周期在两个安全点之间,那么:live 选项将无法探知到这些对象。

    另外,如果某个线程长时间无法跑到安全点,jmap 将一直等下去。与前面讲的 jstat 则不同,垃圾回收器会主动将 jstat 所需要的摘要数据保存至固定位置之中,而 jstat 只需直接读取即可。

    jhat:JDK 自带堆分析工具

    jhat(JVM Heap Analysis Tool):Sun JDK 提供的 jhat 命令与 jmap 命令搭配使用,用于分析 jmap 生成的 heap dump 文件(堆转储快照)。jhat 内置了一个微型的 HTTP/HTML 服务器,生成 dump 文件的分析结果后,用户可以在浏览器中查看分析结果(分析虚拟机转储快照信息)。

    使用了 jhat 命令,就启动了一个 http 服务,端口是 7000,即 http://localhost:7000/,就可以在浏览器里分析。

    说明:jhat 命令在 JDK9、JDK10 中已经被删除,官方建议用 VisualVM 代替。

    基本适用语法:jhat

    option 参数 作用
    -stack false | true 关闭|打开对象分配调用栈跟踪
    -refs false | true 关闭|打开对象引用跟踪
    -port port-number 设置 jhat HTTP Server 的端口号,默认 7000
    -exclude exclude-file 执行对象查询时需要排除的数据成员
    -baseline exclude-file 指定一个基准堆转储
    -debug int 设置 debug 级别
    -version 启动后显示版本信息就退出
    -J 传入启动参数,比如-J-Xmx512m

    示例

    在 jmap 的示例中,我们在 D 盘生成了 5 个 dump 文件,接下来我们直接在命令行使用 jhat 命令,打开 dump 文件。

    jhat d:\3.hprof
    

    image-20220131212831537

    打开浏览器访问 http://localhost:7000/

    image-20220131212920407

    Execute Object Query Language (OQL) query 可以利用 OQL 查询想要的类,如

    select s from java.lang.String s where s.value.length > 100
    

    jstack:打印 JVM 中线程快照

    官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jstack.html

    jstack(JVM Stack Trace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。

    生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用 jstack 显示各个线程调用的堆栈情况。

    在 thread dump 中,要留意下面几种状态

    • 死锁,Deadlock(重点关注)
    • 等待资源,Waiting on condition(重点关注)
    • 等待获取监视器,Waiting on monitor entry(重点关注)
    • 阻塞,Blocked(重点关注)
    • 执行中,Runnable
    • 暂停,Suspended
    • 对象等待中,Object.wait()TIMED_WAITING
    • 停止,Parked
    option 参数 作用
    -F 当正常输出的请求不被响应时,强制输出线程堆栈
    -l 除堆栈外,显示关于锁的附加信息
    -m 如果调用本地方法的话,可以显示 C/C++ 的堆栈

    代码示例(死锁)

    public class ThreadDeadLock {
    ​
        public static void main(String[] args) {
    ​
            StringBuilder s1 = new StringBuilder();
            StringBuilder s2 = new StringBuilder();
    ​
            new Thread(){
                @Override
                public void run() {
                    synchronized (s1){
                        s1.append("a");
                        s2.append("1");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        synchronized (s2){
                            s1.append("b");
                            s2.append("2");
    ​
                            System.out.println(s1);
                            System.out.println(s2);
                        }
    ​
                    }
    ​
                }
            }.start();
    ​
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (s2){
                        s1.append("c");
                        s2.append("3");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        synchronized (s1){
                            s1.append("d");
                            s2.append("4");
    ​
                            System.out.println(s1);
                            System.out.println(s2);
                        }
                    }
                }
            }).start();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    ​
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Map all = Thread.getAllStackTraces();//追踪当前进程中的所有的线程
                    Set entries = all.entrySet();
                    for(Map.Entry en : entries){
                        Thread t = en.getKey();
                        StackTraceElement[] v = en.getValue();
                        System.out.println("【Thread name is :" + t.getName() + "】");
                        for(StackTraceElement s : v){
                            System.out.println("\t" + s.toString());
                        }
                    }
                }
            }).start();
        }
    }
    

    运行后,在命令行使用该命令:

    D:>jps
    8912
    22164 ThreadDeadLock
    18424 Jps
    5084 Launcher
    ​
    D:>jstack 22164
    

    输出的代码:

    2022-01-31 21:51:08
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.231-b11 mixed mode):
    ​
    "DestroyJavaVM" #15 prio=5 os_prio=0 tid=0x0000000002b12800 nid=0x5b50 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "Thread-1" #13 prio=5 os_prio=0 tid=0x000000001e041800 nid=0x9bc waiting for monitor entry [0x000000001fd1f000]
       java.lang.Thread.State: BLOCKED (on object monitor)
            at com.youngkbt.jstack.ThreadDeadLock$2.run(ThreadDeadLock.java:63)
            - waiting to lock  (a java.lang.StringBuilder)
            - locked  (a java.lang.StringBuilder)
            at java.lang.Thread.run(Thread.java:748)
    ​
    "Thread-0" #12 prio=5 os_prio=0 tid=0x000000001e03b800 nid=0x52f8 waiting for monitor entry [0x000000001fc1f000]
       java.lang.Thread.State: BLOCKED (on object monitor)
            at com.youngkbt.jstack.ThreadDeadLock$1.run(ThreadDeadLock.java:35)
            - waiting to lock  (a java.lang.StringBuilder)
            - locked  (a java.lang.StringBuilder)
    ​
    "Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001df8b000 nid=0x3408 runnable [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000001df47000 nid=0x533c waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001df44800 nid=0x4ef8 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001df42800 nid=0x22b8 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001df40000 nid=0x3494 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001df35800 nid=0x2da8 runnable [0x000000001f4fe000]
       java.lang.Thread.State: RUNNABLE
            at java.net.SocketInputStream.socketRead0(Native Method)
            at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
            at java.net.SocketInputStream.read(SocketInputStream.java:171)
            at java.net.SocketInputStream.read(SocketInputStream.java:141)
            at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
            at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
            at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
            - locked  (a java.io.InputStreamReader)
            at java.io.InputStreamReader.read(InputStreamReader.java:184)
            at java.io.BufferedReader.fill(BufferedReader.java:161)
            at java.io.BufferedReader.readLine(BufferedReader.java:324)
            - locked  (a java.io.InputStreamReader)
            at java.io.BufferedReader.readLine(BufferedReader.java:389)
            at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:47)
    ​
    "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001de9e000 nid=0xac waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001def2000 nid=0x2908 runnable [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    ​
    "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001c7c3800 nid=0x1610 in Object.wait() [0x000000001f1df000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on  (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
            - locked  (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
            at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
    ​
    "Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001de83000 nid=0x31e4 in Object.wait() [0x000000001f0de000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on  (a java.lang.ref.Reference$Lock)
            at java.lang.Object.wait(Object.java:502)
            at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
            - locked  (a java.lang.ref.Reference$Lock)
            at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
    ​
    "VM Thread" os_prio=2 tid=0x000000001de62800 nid=0x575c runnable
    ​
    "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002b28800 nid=0x1768 runnable
    ​
    "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002b2a000 nid=0x97c runnable
    ​
    "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002b2c000 nid=0x4364 runnable
    ​
    "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002b2d800 nid=0x4608 runnable
    ​
    "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000002b2f800 nid=0x4f38 runnable
    ​
    "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002b32000 nid=0xb80 runnable
    ​
    "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000002b35000 nid=0xce4 runnable
    ​
    "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000002b36000 nid=0x5510 runnable
    ​
    "GC task thread#8 (ParallelGC)" os_prio=0 tid=0x0000000002b37800 nid=0x193c runnable
    ​
    "GC task thread#9 (ParallelGC)" os_prio=0 tid=0x0000000002b38800 nid=0x1010 runnable
    ​
    "VM Periodic Task Thread" os_prio=2 tid=0x000000001e008000 nid=0x1144 waiting on condition
    ​
    JNI global references: 12
    ​
    ​
    Found one Java-level deadlock:
    =============================
    "Thread-1":
      waiting to lock monitor 0x000000001e044d58 (object 0x000000076ba1e2f0, a java.lang.StringBuilder),
      which is held by "Thread-0"
    "Thread-0":
      waiting to lock monitor 0x000000001c7c2dc8 (object 0x000000076ba1e338, a java.lang.StringBuilder),
      which is held by "Thread-1"
    ​
    Java stack information for the threads listed above:
    ===================================================
    "Thread-1":
            at com.youngkbt.jstack.ThreadDeadLock$2.run(ThreadDeadLock.java:63)
            - waiting to lock  (a java.lang.StringBuilder)
            - locked  (a java.lang.StringBuilder)
            at java.lang.Thread.run(Thread.java:748)
    "Thread-0":
            at com.youngkbt.jstack.ThreadDeadLock$1.run(ThreadDeadLock.java:35)
            - waiting to lock  (a java.lang.StringBuilder)
            - locked  (a java.lang.StringBuilder)
    ​
    Found 1 deadlock.
    

    部分图:(可以看出 BLOCKED 进入死锁阻塞)

    image-20220131215206187

    其他代码示例:

    因为内容结果太长,所以只给代码,在命令行的输入可以自行练习查看(也可以使用 option 参数查看额外内容)。

    线程睡眠代码:

    public class TreadSleepTest {
        public static void main(String[] args) {
            System.out.println("hello - 1");
            try {
                Thread.sleep(1000 * 60 * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    ​
            System.out.println("hello - 2");
        }
    }
    

    线程同步代码:

    public class ThreadSyncTest {
       public static void main(String[] args) {
           Number number = new Number();
           Thread t1 = new Thread(number);
           Thread t2 = new Thread(number);

           t1.setName("线程1");
           t2.setName("线程2");

           t1.start();
           t2.start();
      }
    }

    class Number implements Runnable {
       private int number = 1;

       @Override
       public void run() {
           while (true) {
               synchronized (this) {

                   if (number

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论