一文带你摸清JVM性能监控、故障排查以及案例说明

开篇

给一个系统定位问题的时候,知识、经验是关键基础,数据是依据,工具是运用知识处理数据的手段。今天这里所说的数据包括但不限于异常堆栈、JVM运行日志、垃圾回收日志、线程快照、堆快照等。如何使用分析工具能提升咱们分析数据以及定位并解决问题的效率。这篇文章主要回顾下JVM中故障排查常用的命令以及案例说明。

常用命令

JDK提供了一系列的用于监控、诊断Java进程的工具,它们在JDK安装目录bin目录下,我们该如何使用它去得到有用的信息并分析系统问题以及性能瓶颈呢?下面详细介绍。

jps:JVM进程状态工具

在linux下我们肯定使用过ps -ef | grep java命令查看过正在运行的Java进程,
而在java中也提供了类似的命令,此命令可以列出正在运行的虚拟机进程,并显示虚拟机执行主类名称以及进程的唯一ID。

jps帮助文档:

usage: jps [-help]
       jps [-q] [-mlvV] [<hostid>]

Definitions:
    <hostid>:      <hostname>[:<port>]

执行案例:

jps -l
1228 sun.tools.jps.Jps

option参数说明:

  • -q:输出本地虚拟机进程的ID,省略类名称。
  • -m:输出启动时传递给主类main()方法的参数。
  • -l:输出全类名,如果执行的是JAR包,会输出JAR包路径。
  • -v:输出进程的JVM配置参数。

jstat:JVM统计信息监视工具

此命令可以查看JVM运行状态。可以显示本地或者远程JVM进程中的类加载、内存、垃圾收集、即时编译等运行时数据。

jstat帮助文档:

invalid argument count
Usage: jstat -help|-options
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

Definitions:
  <option>      An option reported by the -options option
  <vmid>        Virtual Machine Identifier. A vmid takes the following form:
                     <lvmid>[@<hostname>[:<port>]]
                Where <lvmid> is the local vm identifier for the target
                Java virtual machine, typically a process id; <hostname> is
                the name of the host running the target Java virtual machine;
                and <port> is the port number for the rmiregistry on the
                target host. See the jvmstat documentation for a more complete
                description of the Virtual Machine Identifier.
  <lines>       Number of samples between header lines.
  <interval>    Sampling interval. The following forms are allowed:
                    <n>["ms"|"s"]
                Where <n> is an integer and the suffix specifies the units as 
                milliseconds("ms") or seconds("s"). The default units are "ms".
  <count>       Number of samples to take before terminating.
  -J<flag>      Pass <flag> directly to the runtime system.

执行案例:

//查看垃圾收集等信息
jstat -gc 1441
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
10752.0 10752.0  0.0    0.0   65536.0   9175.5   175104.0     0.0     4480.0 780.7  384.0   76.6       0    0.000   0      0.000    0.000

option参数说明:

  • -class:监视类加载、卸载数量、总空间以及类装载的耗时。
  • -compiler:即时编译器编译过的方法、耗时等信息。
  • -gc:监视Java堆状态,包括Eden区、两个Survivor区、老年代、永久代的容量、已用空间、垃圾收集时间合计等信息。
  • -gccapacity:内容与gc基本类似,但输出的主要是关注Java堆各个区域使用的最大、最小空间。
  • -gccause:与gcutil功能一样,但是会额外输出上一次导致垃圾收集产生的原因。
  • -gcmetacapacity:JDK8下元数据空间统计。
  • -gcnew:监视新生代垃圾收集信息。
  • -gcnewcapacity:与gcnew类似,输出使用到的最大、最小空间。
  • -gcold:监视老年代垃圾收集信息。
  • -gcoldcapacity:与gcold类似,输出使用到的最大、最小空间。
  • -gcutil:监视内容与gc类似,输出已使用空间占总空间的百分比。
  • -printcompilation:输出已经被即时编译的方法。

jinfo:Java配置信息工具

可以用来查看正在运行的Java程序的扩展参数,包括Java system属性和JVM命令行参数;也可以动态修改正在运行的JVM参数。

jinfo帮助文档:

Usage:
    jinfo [option] <pid>
        (to connect to running process)
    jinfo [option] <executable <core>
        (to connect to a core file)
    jinfo [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)

where <option> is one of:
    -flag <name>         to print the value of the named VM flag
    -flag [+|-]<name>    to enable or disable the named VM flag
    -flag <name>=<value> to set the named VM flag to the given value
    -flags               to print VM flags
    -sysprops            to print Java system properties
    <no option>          to print both of the above
    -h | -help           to print this help message

执行案例:

jinfo -flags 18378
Attaching to process ID 18378, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.261-b12
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=262144000 -XX:MaxHeapSize=4164943872 -XX:MaxNewSize=1388314624 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=87031808 -XX:OldSize=175112192 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 

option参数说明:

  • no option 输出全部的参数和系统属性
  • -flag name 输出对应名称的参数
  • -flag [+|-]name 开启或者关闭对应名称的参数
  • -flag name=value 设定对应名称的参数
  • -flags 输出全部的参数
  • -sysprops 输出系统属性

jmap:Java内存映像工具

jamp命令用于生成堆转储快照。还可以查询finalize执行队列、Java堆和方法区的详细信息,例如空间使用率、当前使用的是哪一种收集器等。

jmap帮助文档:

Usage:
    jmap [option] <pid>
        (to connect to running process)
    jmap [option] <executable <core>
        (to connect to a core file)
    jmap [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)

where <option> is one of:
    <none>               to print same info as Solaris pmap
    -heap                to print java heap summary
    -histo[:live]        to print histogram of java object heap; if the "live"
                         suboption is specified, only count live objects
    -clstats             to print class loader statistics
    -finalizerinfo       to print information on objects awaiting finalization
    -dump:<dump-options> to dump java heap in hprof binary format
                         dump-options:
                           live         dump only live objects; if not specified,
                                        all objects in the heap are dumped.
                           format=b     binary format
                           file=<file>  dump heap to <file>
                         Example: jmap -dump:live,format=b,file=heap.bin <pid>
    -F                   force. Use with -dump:<dump-options> <pid> or -histo
                         to force a heap dump or histogram when <pid> does not
                         respond. The "live" suboption is not supported
                         in this mode.
    -h | -help           to print this help message
    -J<flag>             to pass <flag> directly to the runtime system

执行案例:

jmap -dump:format=b,file=test.bin 1713
Dumping heap to /Users/handexing/test.bin ...
Heap dump file created

参数说明:

  • -dump:生成Java堆转储快照。格式为-dump:[live,]format=b,file=<filename>,其中live参数说明是否只dump出存活对象。
  • -finalization:显示在F-queue中等待Finalizer线程执行finalize方法的对象。
  • -heap:显示Java堆详细信息。例如哪种回收器、参数配置、分代情况等。linux平台下有效。
  • -histo:显示堆中对象统计信息,包括类、实例数量等。
  • -permstat:以classloader为统计口径显示永久代内存状态。linux平台下有效。
  • -F:当JVM对-dump没有响应时,可以使用-F强制生成dump快照,linux平台下有效。

jhat:JVM堆转储快照分析工具

与jmap命令搭配使用,用来分析jmap生成的堆转储快照。jhat内置了一个微型http/web服务器,生成分析后的结果,可以在浏览器中查看(话说回来,实际情况中除非是真没别的工具可用了,否则大多数人是不会直接用jhat来分析快照的)。也不建议在服务器上使用jhat,会损耗服务器性能。

jhat帮助文档:

Usage:  jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file>

    -J<flag>          Pass <flag> directly to the runtime system. For
              example, -J-mx512m to use a maximum heap size of 512MB
    -stack false:     Turn off tracking object allocation call stack.
    -refs false:      Turn off tracking of references to objects
    -port <port>:     Set the port for the HTTP server.  Defaults to 7000
    -exclude <file>:  Specify a file that lists data members that should
              be excluded from the reachableFrom query.
    -baseline <file>: Specify a baseline object dump.  Objects in
              both heap dumps with the same ID and same class will
              be marked as not being "new".
    -debug <int>:     Set debug level.
                0:  No debug output
                1:  Debug hprof file parsing
                2:  Debug hprof file parsing, no server
    -version          Report version number
    -h|-help          Print this help and exit
    <file>            The file to read

For a dump file that contains multiple heap dumps,
you may specify which dump in the file
by appending "#<number>" to the file name, i.e. "foo.hprof#3".

All boolean options default to "true"

执行案例:

jhat test.bin  
Reading from dump.bin...
Dump file created Sat Feb 8 21:54:58 CST 2021
Snapshot read, resolving...
Resolving 271309 objects...
Chasing references, expect 54 dots......................................................
Eliminating duplicate references......................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

访问localhost:7000可以查看分析结果。

jstack:Java堆栈跟踪工具

用于生成JVM当时的线程快照。线程快照就是当前JVM内每一条线程正在执行的方法堆栈集合。生成快照主要用于定位线程长时间停顿的原因,例如死锁、死循环、请求资源导致长时间挂起等。就可以排查到没有相应的线程到底在干什么。

jstack帮助文档:

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

执行案例:

jstack -l 1713
2021-02-08 20:16:16
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.261-b12 mixed mode):

"DestroyJavaVM" #53 prio=5 os_prio=31 tid=0x00007fa898808800 nid=0x1103 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"http-nio-8080-AsyncTimeout" #51 daemon prio=5 os_prio=31 tid=0x00007fa898a4a000 nid=0x7903 waiting on condition [0x0000700007b0b000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at org.apache.coyote.AbstractProtocol$AsyncTimeout.run(AbstractProtocol.java:1133)
    at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
    - None

option参数说明:

  • -F:正常输入不被响应时,强制输出堆栈。
  • -m:如果调用本地方法的话,显示C/C++的堆栈。
  • -l:除堆栈外,显示关于锁的附加信息。

案例说明

OOM分析

Java代码案例:

/**
 * @author handx
 * @version 1.0.0
 * @ClassName Heap.java
 * @Description TODO
 * @createTime 2021年02月08日 20:47:00
 */
public class HeapOOM {

    private static class OOMObject{}

    public static void main(String[] args) {
        ArrayList<OOMObject> oomObjects = new ArrayList<OOMObject>();

        while (true){
            oomObjects.add(new OOMObject());
        }
    }
}

VM opetion配置:

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=./

或使用jmap命令也可以拉取一份堆转储文件。

程序执行完毕打印:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to ./java_pid1824.hprof ...
Heap dump file created [27809333 bytes in 0.075 secs]

使用jvisualvm进行分析(JDK自带的工具)将dump文件导入进来:

image

打开选项卡,可以看到第一个就是我们自己创建的对象:

image

也可以查看堆转储上的线程信息:


image

这个地方基本上已经看出是具体哪一行代码有问题了,该修复修复了。

写在最后

简单介绍了JVM中常用的命令,想要熟练使用还要在日常开发调试中经常使用,熟能生巧。下次复习下怎样对GC日志分析,希望这篇文章能给大家带来帮助。喜欢加关注,后续持续更新!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容