深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具

第四章 虚拟机性能监控与故障处理工具

4.1 概述

经常使用适当的虚拟机监控和分析工具可以加快我们分析数据、定位解决问题的速度。这里所说的数据包括:运行日志、异常堆栈、GC 日志、线程快照(threaddump / javacore 文件)、堆转储快照(headdump / hprof 文件)等

4.2 JDK 的命令行工具

Sun 公司(现在应该是 Oracle 了)其实为Java开发者提供了许多的免费便利工具,虽然他们在软件的使用说明上把他们声明为“没有技术支持并且是实验性质的(unsupported and experimental)的产品”,但事实上这些工具都非常的稳定且强大。如图:
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第1张图片
大家能看到其实大部分的工具类都稳定在16-17KB左右,这其实是因为这些工具类只不过是在 tools.jar 类库的一层薄包装而已。不信我们看下 tools.jar 里都有啥:深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第2张图片
怎么样,有没有看到我们熟悉的东西。jps jstat jmap jstack~
至于Linux上的JDK,实际上是一样的:
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第3张图片
介绍几个常用的:

名称 主要作用
jps JVM Process Status Tool,显示指定系统内所有HotSpot虚拟机进程
jstat JVM Statistics Monitoring Tool,用于收集HotSpot虚拟机各方面的运行数据
jinfo Configuration Info for Java,显示虚拟机配置信息
jmap Memory Map for Java,生成虚拟机的内存转储快照(heapdump文件)
jhat JVM Heap Dump Browser,用于分析 heapdump 文件,他会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果
jstack Stack Trace for Java,显示虚拟机的线程快照(threaddump)

为做以下实验,写了个简单的小程序来模拟正常程序运行:

public class JVMTools {

    public JVMTools() {
        System.out.println(System.currentTimeMillis() + " A New Object (" + this.toString() + ") Created!");
    }
    
 	public static final int _1MB = 1024 * 1024;
    
    // 老规矩,创建一个占点内存的对象,好观测
    private byte[] arr = new byte[2 * _1MB];
    
    private int a = 0;

    public void add() throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            a ++;
            Thread.sleep(100);
        }
        System.out.println(System.currentTimeMillis() + " Object (" + this.toString() + ") execute add method end!");
    }

    public static void main(String[] args) throws InterruptedException {
        while (true) {
            new Thread(() -> {
                JVMTools tmp = new JVMTools();
                try {
                	// 保证他能存活10秒钟
                    tmp.add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

            Thread.sleep(1000);
        }
    }
}

大体意思就是每秒创建一个对象,对象的存活时间为10秒,也就是说理论上内存中总有10个存活对象,用来观察内存的变化。

4.2.1 jps:虚拟机进程状况工具

jps 的作用就是列出当前在运行的 JVM,查出的 LVMID 跟操作系统中的 PID (进程ID)是一致的,
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第4张图片
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第5张图片
jps 的命令格式如下:
jps [options] [hostid] 例如 jps -l
jps 可以通过 RMI协议查询开启了 RMI 服务器的远程虚拟机进程状态,命令中的 hostid 为 RMI 注册表中注册的主机名。jps其他常用选项看下表:

选项 作用
-q 只输出 LVMID ,省略主类的名称
-m 输出虚拟机进程启动时传递给主类 main() 函数的参数
-l 输出主类的全名,如果进城执行的是 Jar 包,则输出包路径
-v 输出虚拟机进程启动时的 JVM 参数

例如:
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第6张图片
4.2.2 jstat:虚拟机统计信息监视工具
jstat(JVM Statistics Monitoring Tool)是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据,在没有 GUI 图形界面,只提供纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。
jstat 命令格式为:
jstat [ option vmid [ interval [ s | ms ] [count] ] ] 例如 jstat -gcutil 20028 100 25
具体选项如下:

选项 作用
-class 监视类装载、卸载数量、总空间及类装载所耗费的时间
-gc 监视Java堆状况,包括 Eden 区、2个 survivor 区、老年代、永久代等的容量,已用空间、 GC 时间合计等信息
-gccapacity 监视内容与 -gc 基本相同,但输出主要关注 Java 堆各个区域使用到的最大和最小空间
-gcuil 监视内容与 -gc 基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与 -gcutil 功能一样,但是会额外输出导致上一次 GC 产生的原因
-gcnew 监视新生代 GC 的状况
-gcnewcapacity 监视内容与 -gcnew 基本相同,输出主要关注使用到的最大和最小空间
-gcold 监视老年代 GC 的状况
-gcoldcapacity 监视内容与 -gcold 基本相同,输出主要关注使用到的最大和最小空间
-compiler 输出JIT编译器编译过的方法,耗时等信息
-printcompilation 输出已经被JIT编译的方法

这些选项太多,不一一实验,仅以最简单的为例:
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第7张图片
这截图代表的意思是 针对 20028 每100 毫秒 记录一次,共记录 25 次GC信息,
字段含义如下:

  • S0:第一个幸存区的使用比例
  • S1:第二个幸存区的使用比例
  • E:Eden 区的使用比例
  • O:Old 区的使用比例
  • M:方法区的使用比例
  • CCS:压缩区的使用比例
  • YGC:年轻代垃圾回收次数
  • YGCT:年轻代垃圾回收消耗时间
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

其余字段都好理解,这个CCS可能会难懂一些,不过当你仔细研读了 JDK8 中的Meta Space 后就知道了。这边我简单讲下,参考博客如下:

  • https://www.cnblogs.com/duanxz/p/3520829.html
  • http://lovestblog.cn/blog/2016/10/29/metaspace/

CCS 全名为 Compressed Class Pointer Space(类指针压缩空间),它实际上是 JDK 8 中元数据区的一部分。前两天的博客中有提到过方法区原来存在永久代中,后来放到了元空间,每个对象实例中都有一个指针指向自己的类信息,也就是我们说的 klass ,那么这个指针就是 _klass 指针,那这个指针在不同的虚拟机中所占的长度也不同。例如 32 位虚拟机中,_klass 指针占 4 字节,但是 64 位虚拟机中 _klass 指针就占了 8 字节。为了压缩对象中的 _klass 指针的大小,引入了 CCS 这么个区域,就是说只有是64位平台上启用了类指针压缩才会存在这个区域。CCS 中只包含类的元数据,剩下的信息还是放在 Meta Space 中。这里这个CCS 字段,实际上指的是 CCS 的已使用率,具体算法是 :

(1-((sun.gc.compressedclassspace.capacity - sun.gc.compressedclassspace.used)/sun.gc.compressedclassspace.capacity)) * 100

capacity 代表的是 CCS 的总容量(在内存中已经 Commit的)大小,used 则代表已经使用的。
在截图中我们可以明显的看到因为新对象的创建导致的 Eden 区使用率上涨。

4.2.3 jinfo:Java 配置信息工具

jinfo 可以用来查看正在运行的 JVM 的各项参数,它还可以通过 -sysprops 参数打印出虚拟机进程的 System.getProperties() 的内容。它也可以通过 -flag [ +|- ] name 或 -flag name=value 两种方式动态的修改正在运行的 JVM 一些参数。当系统崩溃时,jinfo可以从core文件里面知道崩溃的Java应用程序的配置信息。实例如下:
jinfo -sysprops 20028
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第8张图片
jinfo -flags 20028 :
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第9张图片

4.2.4 jmap: Java 内存映像工具

jmap 就是我们常常用来做 heapdump 的主要工具,虽然可以用其他方式(例如 加一些 JVM 启动参数)来生成,但是 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:live,format=b,file=Demo.hprof 20028

创建dump
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第10张图片

4.2.5 jhat:虚拟机转储快照分析工具

JDK 自身提供一种分析dump文件的工具—— jhat(JVM Heap Analysis Tool)命令与 jmap 搭配使用。但是实话说一般人都不用,太难用了。都不如 VisualVM,用的最多的应该还要数 Eclipse Memory Analyzer 和 IBM HeapAnalyzer 两大工具了。不管怎样,写都写了,就展示一下吧:

深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第11张图片
待出现Server is ready字样,输入http://localhost:7000/ 即可查看
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第12张图片

4.2.6 jstack: Java 堆栈跟踪工具

jstack(Stack Track for Java)命令,可以生成当前虚拟机当前时刻的线程快照(threaddump/Javacore)。用以分析是否发生死锁,线程为何反应时间过长等问题。可以看到详细的java栈信息,老规矩不上表格了:

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 20028
# 将栈信息保存在 threaddump.log 文件中
jstack -l 20028 >> threaddump.log

深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第13张图片
这里还能把文件保存下来,为什么要保存呢。因为有这个好东西:
https://www.fastthread.io/
这个网站可以分析你上传的dump文件,帮助快速定位。示例如下:
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第14张图片
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第15张图片
多余的图就不放了,大家感兴趣的自行探索~

4.3 JDK 的可视化工具

JDK 中实际上提供了两种可视化工具,而这两种工具并未被贴上 unsupported and experimental 的标签,那就是 Jconsole 和 VisualVM 。

4.3.1 JConsole:Java 监视与管理控制台

启动
通过目录下的jconsole.exe 启动后,可以直接选择线程而无需使用 jps 再去查
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第16张图片
连接上之后,就可以很直观的看到概览、内存、线程、类等趋势图:
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第17张图片
书中针对工具有不同的例子作解释,此处不再展开说。有兴趣的童鞋可以参考原书自行研究~

4.3.2 VisualVM:多合一处理故障工具

VisualVM 无法直接启动,是需要通过插件启动的。比如我使用的 IntelliJIDEA2019.2.3 。启动的时候带有插件:
深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第18张图片
程序启动后会随之将 VisualVM 一并启动。VisualVM 启动后会出现如下图所示概览,书中对软件使用方法做了详细描述,本文不再赘述,仅挑部分功能截图。

  • 概览:
    深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第19张图片
  • GC 历史可视化
    深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第20张图片
  • 快速dump
    深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第21张图片
  • 快速dump做下来的 heapdump
    深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第22张图片
  • 快速dump做下来的 threaddump
    深入理解Java虚拟机-第四章 虚拟机性能监控与故障处理工具_第23张图片

本章主要是讲解一些随JDK的实用小工具,用时再回来翻阅即可

本文仅是在自我学习 《深入理解Java虚拟机》这本书后进行的自我总结,有错欢迎友善指正。

欢迎友善交流,不喜勿喷~
Hope can help~

你可能感兴趣的:(java,jvm,jdk,jmap,jstat)