JDK的命令行工具

JDK的命令行工具介绍

主要介绍 jpsjstatjinfojmapjhatjstack 等几个JDK命令行工具

(JDK1.8 HotSpot)


数据依据来源

用工具来分析数据,以此来获取结果。下面包含四个数据依据。

  • 运行日志
  • 异常堆栈
  • GC日志
  • 堆转储快照(heapdump/javacore文件)
  • 线程快照(threaddump/hprof文件)

在JDK的bin目录下有很多监视虚拟机和故障处理的工具。文章将讲解多个关于JDK的命令行工具。


1. JPS(JVM Process Status Tool)

描述: 虚拟机进程状态管理工具;其他工具在使用时需要通过该工具来获取LVMID

1.1 功能

  • 列举正在运行的虚拟机进程; 进程本地虚拟机唯一ID(Local Virtaul Machine Identifer LVMID)
  • 显示虚拟机执行主类(main()方法所在的类)的名称

1.2 参数

: options (选项) ; 本文将 options 理解为工具的参数

jps 命令格式: jps [ options ] [hostid]

参数 描述
-l 输出主类的全名,如果是执行的jar,则输出jar的路径
-v 输出JVM启动时的JVM参数

当然常用参数还是 -l ,主要是为了获得ID值。


1.3 实验

编写一个应用程序,然后通过JPS 命令来查阅信息

public class TestJPS {
    public static void main(String[] args) {
        while(true){
        }
    }
}
C:\Program Files\Java\jdk1.8.0_141\bin>jps -l
10048 sun.tools.jps.Jps
6832 org.jetbrains.jps.cmdline.Launcher
976
7092 com.intellij.rt.execution.application.AppMain
4536 org/netbeans/Main
3484

可以获取的到JVMID, 然后用再使用其他命令获取该JMID的详细信息

:JDK1.8 针对这个-l参数有是有变化的。


2 Jstat (JVM Statistics Monitoring Tool)

2.1 描述:虚拟机统计信息监控工具

监视虚拟机各种运行状态信息的命令行工具;

它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,在没有GUI图形化界面,只提供纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。(jstat工具参数还是比较多,信息还是比较丰富)


2.2 命令格式

jstat [options] vmid [interval [s|ms] [count]] ] (远程命令格式略有不同)

jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]


2.3 主要工具参数

参数 功能作用
-class 监视类装载、卸载数量,以及总空间和装载耗时等
-gc 监视堆中 eden、 survivor 、老年代、元空间等空间大小和已使用情况,GC次数、耗时等
-gcmetacapacity 元空间
-gcutil 与gc 类似,但是注重的是占比情况
-printcompilation 输出已经被JIT重新编译的方法
-gcoldcapacity 老年代统计信息
-gcnew 新生代
-gccause 与-gcutil相似,但是会输出上一次GC的原因

2.4 实验

通过实验来验证jstat相关参数。

2.4.1 实验一

使用-gc 命令; 为了能够更加直观,在程序中设置了VM相关参数; 然后运行、查看结果并分析。

/**
 *
  设置初始堆为20M,最大堆为20M,新生代10M. from大小为2M,to大小为2M,eden大小为6M
 -verbose:gc -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M
 -XX:SurvivorRatio=3 -XX:MaxTenuringThreshold=15 -XX:+PrintGCDetails -XX:+PrintTenuringDistribution
 */
public class TestJPS {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        byte[] allocation1, allocation2, allocation3,allocation4;
        allocation1 = new byte[_1MB / 4];
        allocation2 = new byte[4 * _1MB];
        allocation3 = new byte[4 * _1MB];
        //第一次Minor GC, eden区空间不足,将 allocation2 分配到老年代,
        //allocation1 被分配到 from区,allocation1的大小在from区能够装下
        //且没有满足动态年龄判定的条件

        allocation4 = new byte[4 * _1MB];
        //第二次GC,Minor GC 原因 eden去空间不足。allocation3被分配到老年代,
        //allocation1 被分配到 to 区, allocation1 的大小能够在to区装下,
        //同时没有达到动态年龄判定的条件。所以能够存活进入to区。
        while(true){
        }
    }

}

(二)jstat -gc 运行并查看结果

JDK的命令行工具_第1张图片

(二)结果分析

参数 解析
S0C surivor(s0)区域大小
s1c s1区大小
S0U S0的使用大小
S1U S1的使用大小
EC eden可以使用的大小
EU eden已经使用
OC 老年代可以使用的大小
OU 老年代已经使用的带下
MC 元空间可以使用的大小
MU 元空间已经使用的大小
CCSC 压缩类空间大小
CCSU 压缩类已经使用大小
YGC 年轻代垃圾回收次数
YGCT 年轻代垃圾回收总耗时
FGC 老年代垃圾回收次数
FGCT 老年代垃圾回收总耗时
GCT 垃圾回收消耗总时间

(四) GC打印日志

程序去掉循环运行获取GC日志信息。

[GC (Allocation Failure) [DefNew
Desired survivor size 1048576 bytes, new threshold 15 (max 15)
- age   1:     895224 bytes,     895224 total
: 5776K->874K(8192K), 0.0117018 secs] 5776K->4970K(18432K), 0.0117932 secs] [Times: user=0.02 sys=0.02, real=0.01 secs] 
[GC (Allocation Failure) [DefNew
Desired survivor size 1048576 bytes, new threshold 15 (max 15)
- age   2:     895136 bytes,     895136 total
: 4970K->874K(8192K), 0.0098978 secs] 9066K->9066K(18432K), 0.0099464 secs] [Times: user=0.00 sys=0.01, real=0.01 secs] 
Heap
 def new generation   total 8192K, used 5031K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  eden space 6144K,  67% used [0x00000000fec00000, 0x00000000ff00f748, 0x00000000ff200000)
  from space 2048K,  42% used [0x00000000ff200000, 0x00000000ff2da8a0, 0x00000000ff400000)
  to   space 2048K,   0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff600000)
 tenured generation   total 10240K, used 8192K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
   the space 10240K,  80% used [0x00000000ff600000, 0x00000000ffe00020, 0x00000000ffe00200, 0x0000000100000000)
 Metaspace       used 3199K, capacity 4494K, committed 4864K, reserved 1056768K
  class space    used 349K, capacity 386K, committed 512K, reserved 1048576K

总结: GC日志信息与Jstat -gc 打印信息一致。


2.4.2 实验二

-class 参数; 监视类装载、卸载数量、总空间以及装载所耗费的时间。

(一)执行命令

与实验一样使用相同代码

jstat_gc


(二)结果分析

参数 解析
Loaded 加载class的数量
Bytes 占用空间大小
Unloaded 未加载数量
Bytes 未加载占用空间
Time 时间

2.4.3 实验三

元数据空间统计(-gcmetacapacity)


(一)执行命令


(二)结果分析

参数 描述
MCMN 最小元数据容量
MCMX 最大元数据容量
MC 当前元数据空间大小
CCSMN 最小压缩类空间大小
CCSMX 最大压缩类空间大小
CCSC 当前压缩类空间大小
YGC 年轻代垃圾回收次数
FGC 老年代垃圾回收次数
FGCT 老年代垃圾回收消耗时间
GCT 垃圾回收消耗总时间

2.4.4 实验四

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

(一)执行命令

gcutil

参数理解与上面相同。


2.4.5 实验五

使用命令 -gccause, 与gcutil 相似,但是会输出上一次GC发生的原因

(一)执行命令

gccause


如果直接使用文本控制台来监控,这个jstat 工具还是笔记不错的。


注: 其他参数不做实验,可自行做实验去验证。


3 jinfo 工具

jinfo 工具, Java配置信息工具; 通过命令可以查看配置信息参数

参数格式: jinfo [option] ipd


在控制台输入 jinfo ,则会提示相关命令参数,可借助提示执行相关命令。

  -flag          to print the value of the named VM flag
  -flag [+|-]    to enable or disable the named VM flag
  -flag = to set the named VM flag to the given value
  -flags               to print VM flags
  -sysprops            to print Java system properties
            to print both of the above

(一)执行命令

C:\Program Files\Java\jdk1.8.0_141\bin>jinfo -sysprops 7424

参数-sysprops 与 System.getProperites() 代码都能获取进程信息


4 jmap (JVM Memory Map for Java)

该工具命令参数还是比较丰富、能够获取比较详细的信息。

4.1 描述

jmap(JVM Memory Map for java)命令用于生成堆转储快照; 当然还可以使用-XX:HeapDumpOnOutOfMemoryError 参数,可以让虚拟机在OOM异常之后自动生产dump文件。


4.2 功能点

  • 可以获取dump文件,它还可以查询 finalize 执行队列
  • java堆信息
  • 空间使用率、当前使用的那种收集器等

4.3 jmap命令格式

jmap [ option ] vmid


4.4 jmap工具主要选项

选项 作用
-dump 生成Java堆转储快照。 格式 -dump:[live,]format=b,file=< filename >,其中live子参数说明是否只dump出存活的对象
-finalizerinfo 显示F-Queue中等待Finalizer线程执行finalize方法的对象
-heap 显示java堆详细信息,如使用哪种收集器、参数配置、分代状况等
-histo 显示堆中对象统计信息,包括类,实例数量、合计容量
-F 当虚拟机进程对 -dump选项没有响应时,可使用这个选项强制生成dump快照

  • 可以通过输入jmap,让其提示参数。

4.5 实验

通过实验去验证jmap 相关参数信息

4.5.1 实验一

(一)-dump命令参数使用

通过这个命令, 可以 生成java堆转储快照

(二)源码

/**
 * 设置初始堆为20M,最大堆为20M,新生代10M. from大小为2M,to大小为2M,eden大小为6M
 -verbose:gc -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M
 -XX:SurvivorRatio=3 -XX:MaxTenuringThreshold=15 -XX:+PrintGCDetails -XX:+PrintTenuringDistribution
 */
public class TestJPS {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        byte[] allocation1, allocation2, allocation3,allocation4;
        allocation1 = new byte[_1MB / 4];
        allocation2 = new byte[4 * _1MB];
        allocation3 = new byte[4 * _1MB];
        //第一次Minor GC, eden区空间不足,将 allocation2 分配到老年代,
        //allocation1 被分配到 from区,allocation1的大小在from区能够装下
        //且没有满足动态年龄判定的条件

        allocation4 = new byte[4 * _1MB];
        //第二次GC,Minor GC 中 eden去空间不足。allocation3被分配到老年代,
        //allocation1 被分配到 to 区, allocation1 的大小能够在to区装下,
        //同时没有达到动态年龄判定的条件。所以能够存活进入to区。
        while(true){
        }
    }

}

(三)执行命令

C:\Program Files\Java\jdk1.8.0_141\bin>jmap -dump:format=b,file=jmapdump.hprof 9044
Dumping heap to C:\Program Files\Java\jdk1.8.0_141\bin\jmapdump.bin ...
Heap dump file created

生成文件,然后对文件进行分析


(四)分析

使用visualVM打开文件,然后对文件进行分析。

  • 截取堆转储上的线程进行分析

JDK的命令行工具_第2张图片


  • 解析堆转储上的线程
    |选项|解析|
    |:-|:-|
    |"Reference Handler","Finalizer","main",| 排在最前用"" 是线程的名称|
    |daemon|线程类型, 属于线程类型,此处是属于daemon(守护线程)|
    |prio|线程优先级|
    |tid|jvm线程id通过java.lang.Thread.getId()获取|
    |WAITING, RUNNABLE|线程状态|

  • 线程状态转换:
    JDK的命令行工具_第3张图片

(五)补充

常见的一些应用场景

现象 原因
cpu使用率不高但是响应很慢 进行dump,查看是否有很多thread struck在了i/o、数据库等地方,定位瓶颈原因
请求无法响应 多次dump,对比是否所有的runnable线程都一直在执行相同的方法,如果是的,可能是锁了!

4.5.2 实验二

使用finalizerinfo 参数

(一)执行命令

C:\Program Files\Java\jdk1.8.0_141\bin>jmap -finalizerinfo 9484
Attaching to process ID 9484, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.141-b15
Number of objects pending for finalization: 0


4.5.3 实验三

使用-heap ,显示java堆详细信息

(一)源码

package com.jvm;

/**
 * 设置初始堆为20M,最大堆为20M,新生代10M. from大小为2M,to大小为2M,eden大小为6M
 -verbose:gc -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M
 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+PrintGCDetails -XX:+PrintTenuringDistribution
 */
public class TestJPS {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        byte[] allocation1, allocation2, allocation3,allocation4;
        allocation1 = new byte[_1MB / 4];
        allocation2 = new byte[4 * _1MB];
        allocation3 = new byte[4 * _1MB];
        //第一次Minor GC, eden区空间不足,将 allocation2 分配到老年代,
        //allocation1 被分配到 from区,allocation1的大小在from区能够装下
        //且没有满足动态年龄判定的条件

        allocation4 = new byte[4 * _1MB];
        //第二次GC,Minor GC 中 eden去空间不足。allocation3被分配到老年代,
        //allocation1 被分配到 to 区, allocation1 的大小能够在to区装下,
        //同时没有达到动态年龄判定的条件。所以能够存活进入to区。
        while(true){
        }
    }

}

(二)执行命令

运行打印结果:

C:\Program Files\Java\jdk1.8.0_141\bin>jmap -heap 11220
Attaching to process ID 11220, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.141-b15

using thread-local object allocation.
Mark Sweep Compact GC

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 20971520 (20.0MB)
   NewSize                  = 10485760 (10.0MB)
   MaxNewSize               = 10485760 (10.0MB)
   OldSize                  = 10485760 (10.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 9437184 (9.0MB)
   used     = 4249104 (4.0522613525390625MB)
   free     = 5188080 (4.9477386474609375MB)
   45.025126139322914% used
Eden Space:
   capacity = 8388608 (8.0MB)
   used     = 4249016 (4.052177429199219MB)
   free     = 4139592 (3.9478225708007812MB)
   50.652217864990234% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 88 (8.392333984375E-5MB)
   free     = 1048488 (0.9999160766601562MB)
   0.008392333984375% used
To Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
tenured generation:
   capacity = 10485760 (10.0MB)
   used     = 9279920 (8.850021362304688MB)
   free     = 1205840 (1.1499786376953125MB)
   88.50021362304688% used

1732 interned Strings occupying 155648 bytes.


(三)参数解析

数据项 描述
using thread-local object allocation 启用线程本地对象分配
Mark Sweep Compact GC 使用’标记整理’收集器
Heap Configuration: 堆配置
Heap Usage: 堆使用
CompressedClassSpaceSize
MaxMetaspaceSize
G1HeapRegionSize

(四) 什么是 CompressedClassSpaceSize

  • 在Java8以前,有一个选项是UseCompressedOops, 所谓OOPS是指ordinary object pointers,就是原始指针。
  • Java Runtime可以用这个指针直接访问指针对应的内存,做相应的操作(比如发起GC时做copy and sweep)。
  • 64bit的JVM出现后,OOPS的尺寸也变成了64bit,比之前的大了一倍。
  • 这样占的内存变为double了,并且同尺寸的CPU Cache要少存一倍的OOPS。
  • 使用这个UseCompressedOops选项。打开后,OOPS变成了32bit。
  • Java8,去掉永久代,使用元空间,存储jvm中的元数据,包括byte code,class等信息。
  • Java8在UseCompressedOops之外,额外增加了一个新选项叫做·UseCompressedClassPointer·。
  • 这个选项打开后,class信息中的指针也用32bit的Compressed版本。而这些指针指向的空间被称作Compressed Class Space。默认大小是1G,但可以通过CompressedClassSpaceSize调整

如果你的java程序引用了太多的包,有可能会造成这个空间不够用,于是会看到

java.lang.OutOfMemoryError: Compressed class space

这时,一般调大CompreseedClassSpaceSize就可以了


4.5.4 实验四

使用 histo 命令

(一)执行命令

C:\Program Files\Java\jdk1.8.0_141\bin>jmap -histo 11220

 num     #instances         #bytes  class name
----------------------------------------------
   1:            31       12870640  [B
   2:          2588         331360  [C
   3:           621          70688  java.lang.Class
   4:          2411          57864  java.lang.String
   5:           146          39264  [I
   6:           595          34296  [Ljava.lang.Object;
   7:           838          33520  java.util.TreeMap$Entry
   8:           116           8352  java.lang.reflect.Field
   9:           198           8072  [Ljava.lang.String;
  10:           150           4800  java.util.Hashtable$Entry
  11:            73           4672  java.net.URL
  12:           104           4160  java.lang.ref.SoftReference
  13:           256           4096  java.lang.Integer
  14:           122           3904  java.util.HashMap$Node
  15:            96           3072  java.util.concurrent.ConcurrentHashMap$Node
......省略下面的更多的信息

4.5.5 实验五

-F 当对-dump 生成文件时没有发反应,可以使用该命令强制生成dump快照。(实验结果存在问题,不做描述)


5 jhat(JVM Heap Analysis Tool)

不推荐使用,有更好的方案;也不做介绍了。


6 jstack(JVM Stack Trace for java)

6.1 描述

  • jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump 或者javacore文件);
  • 线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因如线程间死锁死循环请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因、
  • 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做了些什么事情,或者等待着什么资源

6.2 jstack 命令格式

jstack [ option ] vmid


6.3 jstack 工具主要选项

jstatck的选项参数进行列举,并描述其作用

参数 作用
-F 当正常输出的请求不被响应时,强制输出线程堆栈
-l 除堆栈外,显示关于锁的附加信息
-m 如果调用本地方法的话,可以显示 c/C++的堆栈

6.4 实验

6.4.1 实验一

使用 jstack -l 参数

(一)执行命令

C:\Program Files\Java\jdk1.8.0_141\bin>jstack -l 11220
2018-04-20 15:48:03
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.141-b15 mixed mode):

"Monitor Ctrl-Break" #10 daemon prio=5 os_prio=0 tid=0x00000000534ec800 nid=0x2780 runnable [0x0000000053c8e000]
   java.lang.Thread.State: RUNNABLE
        at java.net.DualStackPlainSocketImpl.accept0(Native Method)
        at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
        at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
        at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
        - locked <0x00000000ff000c68> (a java.net.SocksSocketImpl)
        at java.net.ServerSocket.implAccept(ServerSocket.java:545)
        at java.net.ServerSocket.accept(ServerSocket.java:513)
        at com.intellij.rt.execution.application.AppMain$1.run(AppMain.java:79)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x000000005282e800 nid=0x2c20 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C1 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000527ff800 nid=0x21cc waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000527b6000 nid=0x2038 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x00000000527b0800 nid=0x2988 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000005279e800 nid=0x8c4 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000005279d000 nid=0x2a28 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000052770800 nid=0x2a30 in Object.wait() [0x0000000052d3e000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000ffa15ac0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x00000000ffa15ac0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
        - None

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000052729000 nid=0x2d6c in Object.wait() [0x0000000052bff000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000ffa15c78> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x00000000ffa15c78> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
        - None

"main" #1 prio=5 os_prio=0 tid=0x0000000002548000 nid=0x2a20 runnable [0x0000000002a7e000]
   java.lang.Thread.State: RUNNABLE
        at com.jvm.TestJPS.main(TestJPS.java:25)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

   Locked ownable synchronizers:
        - None

"VM Thread" os_prio=2 tid=0x0000000052720800 nid=0x28d4 runnable

"VM Periodic Task Thread" os_prio=2 tid=0x00000000534a8800 nid=0x2a94 waiting on condition

JNI global references: 15


(二)分析

这个命令与 jmap -dump:format=b,file=jmapdump.hprof 都能打印线程信息。

参数 解析
nid 系统线程id(NativeThread ID)nid=0xaef,和top命令查看的线程pid对应,不过一个是10进制,一个是16进制

其他信息可以参考前面的jmap快照进行学习


参考

  • visualVM官网
  • java高分局之jstat命令使用
  • 性能分析之-- JAVA Thread Dump 分析综述
  • JVM调优中,压缩类空间(Compressed Class space)如何理解,有多重要?
  • 《深入理解Java虚拟机》–周志明

结束语

理论知识是实践的指导工具,将知识应用到实际项目才是真正的目的。

你可能感兴趣的:(JVM,深入理解Java虚拟机)