1.为什么需要JDK原生命令

在开发或测试环境中,我们可以通过可视化工具进行JVM的监控以及分析。但是往往在线上环境,因为安全以及性能,或者可视化工具部分功能不支持等原因,无法使用可视化工具进行JVM的监控以及分析。这时候JDK原生命令就可以派上用场了

2.JDK原生命令概述

JDK原生命令都是通过%JAVA_HOME%/lib/tools.jar包里面的Java方法来实现的,所以如果你想自己打造一个属于自己的JVM监控系统,那在Java程序内部调用该jar包的方法即可实现。
原生命令主要包括:jps、jinfo、jstat、jstack、jmap、jhat等命令,提供了查看虚拟机程序运行日志、异常堆栈信息、GC日志记录、线程快照文件、堆内存快照文件等相关功能
官方文档:JDK工具参考文档。同时可通过 ${命令} -help的形式获取其主要用法

3.jps(进程查看)

主要作用

jps的主要作用是用来查看机器上运行的Java进程,类似于Linux系统的ps -ef | grep java命令。jps工具也支持查看其他机器的Java进程,命令格式如下:

命令格式

jps [ options ] [ hostid ]

主要参数

image.png
其中[options]主要有-q、-m、-l、-v、-V几个选项:

  • jps -q:查看机器所有运行的Java进程,但只显示进程号(lvmid)。
  • jps -m:~,只显示传递给main方法的参数。
  • jps -l:~,只显示运行程序主类的包名,或者运行程序jar包的完整路径。
  • jps -v:~,单独显示JVM启动时,显式指定的参数。
  • jps -V:~,显示主类名或者jar包名。

其中[hostid]是用来连接其他机器查看Java进程的远程ID。

常用参数

jps -l(查看当前服务器运行的java进程)
image.png

4.jinfo(配置查看)

主要作用

主要用于实时查看JVM的运行参数,也可以在运行时动态的调整一些参数

命令格式

jinfo [ option1 ] [ option2 ]

主要参数

image.png
其中[option1]可选项如下:

  • :第一个参数不写,默认输出JVM的全部参数和系统属性。
  • -flag :输出与指定名称对应的所有参数,以及参数值。
  • -flag [+|-]:开启或者关闭与指定名称对应的参数。
  • -flag =:设置与指定名称对应参数的值。
  • -flags:输出JVM全部的参数。
  • -sysprops:输出JVM全部的系统属性。

其中[option2]可选项如下:

  • :对应的JVM进程ID(必需参数),指定一个jinfo要操作的Java进程。
  • executable <core:输出打印堆栈跟踪的核心文件。
  • [server-id@]:远程操作的地址。

    • server-id:远程debug服务的进程ID;
    • remote server IP/hostname:远程debug服务的主机名 或 IP地址;

      常用参数

      jinfo -flags ${pid}(查看当前进程虚拟机全部参数)
      image.png

      5.jstat(统计信息查看)

      主要作用

      jstat的全称为“Java Virtual Machine statistics monitoring tool”,该工具可以利用JVM内建的指令对Java程序的资源以及性能进行实时的命令行的监控,监控范围包含:堆空间的各数据区、垃圾回收状况以及类的加载与卸载状态。

      命令格式

      jstat -
  • [option]:监控参数选项。

  • -t:在输出结果中加上Timestamp列,显示系统运行的时间。
  • -h:可以在周期性数据输出的时候,指定间隔多少行数据后输出一次表头。
  • vmid:Virtual Machine ID虚拟ID,也就是指定一个要监控的Java进程ID。
  • interval:每次执行的间隔时间,默认单位为ms。
  • count:用于指定输出多少条数据,默认情况下会一直输出。

执行命令jstat -option后,可以看到存在很多选项,如下:

  • -class:输出类加载ClassLoad相关的信息。
  • -compiler:显示与JIT即时编译相关的信息。
  • -gc:显示与GC相关的信息。
  • -gccapacity:显示每个分代空间的容量以及使用情况。
  • -gcmetacapacity:输出元数据空间相关的信息。
  • -gcnew:显示新生代空间相关的信息。
  • -gcnewcapacity:显示新生代空间的容量大小以及使用情况。
  • -gcold:输出年老代空间的信息。
  • -gcoldcapacity:输出年老代空间的容量大小以及使用情况。
  • -gcutil:显示垃圾回收信息。
  • -gccause:和-gcutil功能相同,但是会额外输出最后一次或本次GC的诱因。
  • -printcompilation:输出JIT即时编译的方法信息。

    常用参数

    jstat -gc -t -h30 106368 2s 100

  • -gc:监控GC的状态

  • -t:显示系统运行的时间
  • -h30:间隔30行数据,输出一次表头
  • 9895:Java进程ID
  • 1s:时间间隔
  • 300:本次输出的数据行数

image.png

字段 含义
Timestamp 系统运行的时间
S0C 第一个Survivor区的总容量大小
S1C 第二个Survivor区的总容量大小
S0U 第一个Survivor区的已使用大小
S1U 第二个Survivor区的已使用大小
EC Eden区的总容量大小
EU Eden区的已使用大小
OC Old区的总容量大小
OU Old区的已使用大小
MC Metaspace区的总容量大小
MU Metaspace区的已使用大小
CCSC CompressedClassSpace空间的总大小
CCSU CompressedClassSpace空间的已用大小
YGC 从程序启动到采样时,期间发生的新生代GC次数
YGCT 从程序启动到采样时,期间新生代GC总耗时
FGC 从程序启动到采样时,期间发生的年老代GC次数
FGCT 从程序启动到采样时,期间年老代GC总耗时
GCT 从程序启动到采样时,程序发生GC的总次数

其他options示例
image.png
其他options参数说明

字段 含义
S0 第一个Survivor区的使用率(S0U/S0C)
S1 第二个Survivor区的使用率(S1U/S1C)
E Eden区的使用率(EU/EC)
O Old区的使用率(OU/OC)
M Metaspace区的使用率(MU/MC)
CCS CompressedClassSpace区的使用率(CCSU/CCSC)
NGCMN 新生代空间初始容量
NGCMX 新生代空间最大容量
S0CMN 第一个Survivor区的初始容量
S0CMX 第一个Survivor区的最大容量
S1CMN 第二个Survivor区的初始容量
S1CMX 第二个Survivor区的最大容量
OGCMN 年老代空间初始容量
OGCMX 年老代空间最大容量
MCMN 元数据空间初始容量
MCMX 元数据空间最大容量
CCSMN 类压缩空间初始容量
CCSMX 类压缩空间最大容量
TT 对象晋升的最小年龄阈值
MTT 对象晋升的最大年龄阈值
DSS 期望的Survivor区总大小

Class加载
image.png

字段 含义
Loaded JVM已经装载的类数量
Bytes 已装载的类占用字节数大小
Unloaded 已经卸载的类数量
Bytes 已卸载的类占用字节数大小
Time 卸载和装载类共耗时

JIT即时编译
image.png

字段 含义
Compiled 编译任务执行的总次数
Failed 编译任务执行失败的次数
Invalid 编译任务执行失效的次数
Bytes 已卸载的类占用字节数大小
Time(options=) 所有编译任务的总耗时
FailedType 最后一个编译失败的任务类型
FailedMethod 最后一个编译失败的任务所在的类及方法

6.jmap(内存查看(主要是堆区))

主要作用

jmap是一个多功能的工具,主要是用于查看堆空间的使用情况,通常会配合jhat工具一起使用,它可以用于生成Java堆的Dump文件。但除此之外,也可以查看finalize队列、元数据空间的详细信息,Java堆中对象统计信息,如每个分区的使用率、当前装配的GC收集器等。

命令格式

jmap [ option1 ] [ option2 ]

主要参数

image.png
其中[option1]可选项有:

  • [no option]:查看进程的内存映像信息,与Solaris pmap类似。
  • -heap:显示Java堆空间的详细信息。
  • -histo[:live]:显示Java堆中对象的统计信息。
  • -clstats:显示类加载相关的信息。
  • -finalizerinfo:显示F-Queue队列中等待Finalizer线程执行finalizer方法的对象。
  • -dump::生成堆转储快照。
  • -F:当正常情况下-dump和-histo执行失效时,前面加-F可以强制执行。
  • -help:显示帮助信息。
  • -J:指定传递给运行jmap的JVM参数。

其中[option2]与jinfo工具的相差无几,可选项如下:

  • :对应的JVM进程ID(必需参数),指定一个jinfo要操作的Java进程。
  • executable <core:输出打印堆栈跟踪的核心文件。
  • [server-id@]:远程操作的地址。

    • server-id:远程debug服务的进程ID;
    • remote server IP/hostname:远程debug服务的主机名 或 IP地址;

      常用参数

      查看堆区信息

      jmap -heap
      image.png
      如图可以直观的看出当前堆空间,新生代(Eden区,from区,to区)和老年代总内存,使用内存,空闲内存,以及内存使用率等信息

      堆区文件转储

      jmap -dump:live,format=b,file=Dump.phrof
      image.png
      如图,jmap命令可进行堆区文件的转储(dump)操作。后续可通过jhat或将文件复制到本地进行可视化分析。
      一般线上机器都不开通远程端口,所以可以通过git、服务器中转再xftp拉取、挂到nginx等方式将线上服务器的堆转储文件拉取到本地
      堆转储文件一般都比较大,所以记得拉取到本地后把服务器上的文件删除
      例如使用VisualVM分析堆转储文件,如图:
      image.png
      image.png
      image.png
      如上图所示,可清晰的获取堆区对象总数,总字节数,GCRoot数等信息,同时可获取当前堆区占用内存最大的对象排名。便于分析内存溢出或内存泄漏问题

      7.jhat(堆内存文件分析)

      主要作用

      这个命令比较鸡肋
      jhat工具一般配合jmap工具使用,主要用于分析jmap工具导出的Dump文件,其中也内嵌了一个微型的HTTP/HTML服务器,所以当jhat工具分析完Dump文件后,可以支持在浏览器中查看分析结果。(http://localhost:7000
      不过在线上环境中一般不会直接使用jhat工具对Dump文件进行解析,因为jhat解析Dump文件,尤其是大体积的Dump时,是一个非常耗时且占用硬件资源的过程。所以为了防止占用服务器过多的资源,通常都会将Dump文件copy到其他机器或本地中分析。
      不过话说回来,到了本地一般也不会使用jhat,因为分析之后生成的结果通过浏览器观察时很难看,一般都会选择VisualVM、MAT(Eclipse Memory Analyzer)、IBM HeapAnalyzer、Jprofile等工具。

      命令格式/主要参数/常用参数

      参考:点击这里

      8.jstack(线程查看)

      主要作用

      jstack工具主要用于捕捉JVM当前时刻的线程快照,线程快照是JVM中每条线程正在执行的方法堆栈集合。在线上情况时,生成线程快照文件可以用于定位线程出现长时间停顿的原因,如线程死锁、死循环、请求外部资源无响应等等原因导致的线程停顿。
      当线程出现停顿时,可以通过jstack工具生成线程快照,从快照信息中能查看到Java程序内部每条线程的调用堆栈情况,从调用堆栈信息中就可以清晰明了的看出:发生停顿的线程目前在干什么,在等待什么资源等。
      同时,当Java程序崩溃时,如果配置好了参数,生成了core文件,咱们也可以通过jstack工具从core文件中提取Java虚拟机栈相关的信息,从而进一步定位程序崩溃的原因。

      命令格式

      jstack [option1] [option2]

      主要参数

      image.png
      其中[option1]可选项为:
  • -l:除开显示堆栈信息外,额外输出关于锁相关的附加信息(用于排查死锁问题)。

  • -m:如果线程调用到本地方法栈中的本地方法,也显示C/C++的堆栈信息。

其中[option2]可选项如下:

  • :对应的JVM进程ID(必需参数),指定一个jinfo要操作的Java进程。
  • executable <core:输出打印堆栈跟踪的核心文件。
  • [server-id@]:远程操作的地址。

    • server-id:远程debug服务的进程ID;
    • remote server IP/hostname:远程debug服务的主机名 或 IP地址;

      常用参数

      线程文件转储

      jstack -l > ${filepath}/${filename}.tdump
      image.png
      后续将服务器上的线程转储文件拉取到本地通过可视化工具分析
      例如使用VisualVM分析线程转储文件,如图:
      image.png
      image.png
      如上图所示,可清晰的获取当前应用所有线程信息,进而分析线程死锁等情况的发生。线程转储文件主要关注以下信息:
  • runnable,线程处于执行中

  • deadlock,死锁(重点关注)
  • blocked,线程被阻塞 (重点关注)
  • Parked,停止
  • locked,对象加锁
  • waiting,线程正在等待
  • waiting to lock 等待上锁
  • Object.wait(),对象等待中
  • waiting for monitor entry 等待获取监视器(重点关注)
  • Waiting on condition,等待资源(重点关注),最常见的情况是线程在等待网络的读写

    9.总结

    通过以上的命令说明,可以了解到JDK原生虚拟机分析命令(工具)的用法。总结如下
虚拟机指令 常用指令格式 作用
jps jps -l 查看java进程
jinfo jinfo /jinfo -flags 查看当前进程系统/虚拟机配置信息
jstat jstat -gc -t -h30 3s 300 查看当前进程虚拟机各种统计信息(堆区内存、类加载等)
jmap jmap -heap
jmap -dump:live,format=b,file=test.phrof
查看堆区详细信息/堆区文件转储(dump)
jhat 没用过 分析堆区文件(鸡肋命令,因为性能问题基本不用)
jstack jstack -l
jstack -l > /data/file/test.tdump
查看线程详细信息/线程文件转储(dump)

一般来说的顺序

  1. jps -l 获取进程信息
  2. jmap -heap pid 获取当前堆区详细信息
  3. jstat -gc -t -h30 pid 3s 300 获取垃圾回收信息
  4. jmap -dump:live,format=b,file=test.phrof pid 将当前堆区信息转储(dump)文件
  5. jstack -l pid > test.tdump 将当前线程信息转储(dump)文件
  6. jinfo -flags pid 查看当前应用程序(进程)虚拟机启动参数并进行修改