虚拟机的监控工具

定位问题,知识储备是基础,日志等数据是依据,工具则是帮助我们事半功倍的手段。

本文是在win下测试,主要介绍一些工具的使用。

1.jps:虚拟机进程状况工具

JVM Process Status Tool

可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)名称以及这些进程的本地虚拟机唯一ID(LVMID,Local Virtual Machine Identifier)。

C:Users***Desktop64124-深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)_源码>jps -l
39172 sun.tools.jps.Jps
24396
24476 org.jetbrains.jps.cmdline.Launcher

2.jstat:虚拟机统计信息工具

JVM Statistics Monitoring Tool

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

C:Users***Desktop64124-深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)_源码>jstat -gcutil 24476
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
 75.50   0.00  76.86   0.20  97.04  92.93      2    0.009     0    0.000    0.009

查询结果表明:这台服务器的新生代Eden区(E,表示Eden)使用了76.8%的空间,2个Survivor区(S0、S1,表示Survivor0、Survivor1),老年代(O,表示Old)和永久代(P,表示Permanent)则分别使用了0.2%和97.4%的空间(这里没有P只有M,对照看的话应该就是P)。程序运行以来共发生MinorGC(YGC,表示Young GC)2次,总耗时0.1009秒;发生Full GC(FGC,表示Full GC)0次,总耗时(FGCT,表示Full GC Time)为0秒;所有GC总耗时(GCT,表示GC Time)为0.009秒。

3.jinfo:Java配置信息

configuration info for java

这里也就是查-XX:....这类的配置

C:Users***Desktop64124-深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)_源码>jinfo -flag CMSInitiatingOccupancyFraction 24476
-XX:CMSInitiatingOccupancyFraction=-1

4.jmap:java内存映像工具

memory map for java

jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)。如果不使用jmap命令,要想获取Java堆转储快照也还有一些比较“暴力”的手段:譬如在第2章中用过的-XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机在内存溢出异常出现之后自动生成堆转储快照文件,通过-XX:+HeapDumpOnCtrlBreak参数则可以使用[Ctrl]+[Break]键让虚拟机生成堆转储快照文件,又或者在Linux系统下通过Kill-3命令发送进程退出信号“恐吓”一下虚拟机,也能顺利拿到堆转储快照。对于IDEA的话还有快捷键。

C:Users***Desktop64124-深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)_源码>jmap -dump:format=b,file=eclipse.bin 24476
Dumping heap to C:UsershufanDesktop64124-深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)_源码eclipse.bin ...
Heap dump file created

5.jhat:堆转储快照分析

jvm heap analysis tool

主要是分析jmap的堆快照,基本没人用

C:Users***Desktop64124-深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)_源码>jhat eclipse.bin
Reading from eclipse.bin...
Dump file created Mon Feb 03 13:25:03 CST 2020
Snapshot read, resolving...
Resolving 3026440 objects...
Chasing references, expect 605 dots............................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
....
Eliminating duplicate references...............................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
.
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

这时打开浏览器输入   http://localhost:7000/  可以看分析结果了。

6.jsatck:java堆栈跟踪工具

stack trace for java

这个主要是查看各个线程堆栈

C:Users***Desktop64124-深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)_源码>jstack 24396
2020-02-03 13:29:05
Full thread dump OpenJDK 64-Bit Server VM (25.202-b44 mixed mode):

"JobScheduler FJ pool 4/7" #170 daemon prio=4 os_prio=-1 tid=0x00000000242dd000 nid=0x2d6c waiting on condition [0x000000004662f000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000e33ce9b0> (a java.util.concurrent.ForkJoinPool)
        at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

"JobScheduler FJ pool 3/7" #169 daemon prio=4 os_prio=-1 tid=0x00000000242dc800 nid=0x9770 waiting on condition [0x000000004652f000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000e33ce9b0> (a java.util.concurrent.ForkJoinPool)
        at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

从JDK 5起,java.lang.Thread类新增了一个getAllStackTraces()方法用于获取虚拟机中所有线程的StackTraceElement对象。使用这个方法可以通过简单的几行代码完成jstack的大部分功能。

java的一些命令行工具,可以自行google,这种东西没必要记,只需要在大脑里有印象即可。

介绍两个可视化工具

jhsdb,这个工具貌似只有openjdk才有。

案例分析。

/**
 * staticObj、instanceObj、localObj存放在哪里?
 */
public class JHSDBTestCase {

    static class Test {
        static ObjectHolder staticObj = new ObjectHolder();
        ObjectHolder instanceObj = new ObjectHolder();

        void foo() {
            ObjectHolder localObj = new ObjectHolder();
            System.out.println("done");    // 这里设一个断点
        }
    }

    private static class ObjectHolder {}

    public static void main(String[] args) {
        Test test = new JHSDBTestCase.Test();
        test.foo();
    }
}

这个不用工具分析也可以知道,staticObj随着Test的类型信息存放在方法区,instanceObj随着Test的对象实例存放在Java堆,localObject则是存放在foo()方法栈帧的局部变量表中。

这里我们用工具分析

1.命令行进入图形化界面

jhsdb hsdb --pid 11180(你当前运行的线程)

2.点击菜单中的Tools->Heap Parameters[插图],结果如图4-5所示,因为笔者的运行参数中指定了使用的是Serial收集器,图中我们看到了典型的Serial的分代内存布局,Heap Parameters窗口中清楚列出了新生代的Eden、S1、S2和老年代的容量(单位为字节)以及它们的虚拟内存地址起止范围。

3.使用scanoops命令在Java堆的新生代(从Eden起始地址到To Survivor结束地址)范围内查找ObjectHolder的实例,结果如下所示:

 

可见这三个对象全部落在了新生代Eden,我们继续分析,再使用revptrs

这个命令大致的作用就是通过反推实例地址,然后我们再用Tool里的inspector工具

 JDK 7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射Class对象存放在一起,存储于Java堆之中,从我们的实验中也明确验证了这一点[插图]。

然后第二个对象

这次找到一个类型为JHSDB_TestCase$Test的对象实例,在Inspector中该对象实例显示如图4-8所示。

 第三个方法栈却不行了。

看来revptrs命令并不支持查找栈上的指针引用,不过没有关系,得益于我们测试代码足够简洁,人工也可以来完成这件事情。在Java Thread窗口选中main线程后点击Stack Memory按钮查看该线程的栈内存,如图4-9所示。

 肉眼看!

参考周志明老师《深入理解Java虚拟机》

一个没有高级趣味的人。 email:hushui502@gmail.com
原文地址:https://www.cnblogs.com/CherryTab/p/12255451.html