JDK监控和故障处理工具(深入理解Java虚拟机笔记)

JDK 命令行工具

jps

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

命令格式为。

jps [ options ] [ hostid ]

其中选项option代表用户希望查询的虚拟机信息,主要分为三类:类加载,垃圾收集,运行期编译状况,常用的option选项如下

如下图所示,210636是本地虚拟机唯一ID。

(1)jps -l 输出主类的全名

(2)jps -v 输出虚拟机进程启动时JVM参数

(3)jps -m 输出传递给Java进程main函数的参数

 

jstat

监视虚拟机各种运行状态信息。它可以显示本地或远程虚拟机进程中的类加载,内存,垃圾收集,即使编译等运行时数据。

命令格式如下。参数interval和count代表查询间隔和次数,若省略则只查询一次,比如 jstat -gc 2764 250 20 意思为每250毫秒查询一次进程2764垃圾收集状况,一共查询20次

jstat [ option vmid [interval[s|ms] [count]] ]

如果是本地虚拟机进程,vmid与lvmid是一致的;若是远程虚拟机进程,则vmid的格式应为:

[protocol:][//]lvmid[@hostname[:port]/servername]

测试:监视一台服务器的内存状况:

jstat -gcutil 2764

S0      S1     E       O        P           YGC YGCT     FGC FGCT    GCT

0.00  0.00  6.20   41.42    47.20     16     0.105        3     0.472    0.577

服务器的新生代Eden使用了6.2%的空间,2个Survivor区(S0,S1)里面为空,老年代Old和永久代Permanent分别使用了41/42%和47.20%的空间。程序运行以来共发生Minor GC(YGC,表示Young GC)16次,总耗时0.105秒;发生Full GC(FGC,表示Full GC)3次,总耗时(FGCT,表示Full GC Time)为0.472秒;所有GC总耗时(GCT,表示GC Time)为0.577秒。

 

jinfo

实时查看和调增虚拟机各项参数。前面提到的jps命令的-v参数可以查看虚拟机启动时显示指定的参数列表,但如果想知道未被显示指定的参数的系统默认值,可以使用jinfo的 -flag进行查询。

测试:如果我们希望查看虚拟机是否使用了某个收集器,如下所示。结果是+表示使用的是CMS收集器;若冒号后面跟的是-,则表示不是使用给定的收集器

jinfo -flag UseConcMarkSweepGC 210636

-XX:+UseConcMarkSweepGC

测试:查询CMSInitiatingOccupancyFraction参数值

jinfo -flag  CMSInitiatingOccupancyFraction 210636
-XX:CMSInitiatingOccupancyFraction=-1

 

jmap

生成堆存储快照。同时也可以查询finalize执行队列,Java堆和方法区的信息(如空间使用率,当前使用的是哪种收集器等)。

测试:在F盘生成a.bin堆存储快照(注:须在管理员模式下cmd)。可通过Visual 等工具分析文件

jmap -dump:format=b,file=F:\a.bin  210636

Dumping heap to F:\a.bin ...
Heap dump file created

 

jhat

与jmap搭配使用,用于分析其生成的堆转储快照。jhat内置一个微型的HTTP/Web服务器,使用户可以在浏览器查看分析结果。

测试:http://localhost:7000/中查看前面生成的堆存储快照

jhat f:\a.bin

...省略前面输出

Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

 

 

jstack

生成虚拟机当前时刻的线程快照(当前虚拟机内每一条线程正在执行的方法堆栈的集合)。生成线程快照的目的是定位线程出现长时间听到的原因,如线程间死锁,死循环等。

测试:下面是一段死锁代码

public class JavaVM {
    private static Object resource1 = new Object();
    private static Object resource2 = new Object();

    public static void main(String[] args) throws Exception {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting get resource2");
                    synchronized (resource2) {
                        System.out.println(Thread.currentThread() + "get resource2");
                    }
                }
            }
        }, "线程 1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting get resource1");
                    synchronized (resource1) {
                        System.out.println(Thread.currentThread() + "get resource1");
                    }
                }
            }
        }, "线程 2").start();
    }
}

通过监视器jstack命令分析:

jstack 148688

Found one Java-level deadlock:
=============================
"线程 2":
  waiting to lock monitor 0x0000000002bfaf98 (object 0x000000076bc2a1b8, a java.lang.Object),
  which is held by "线程 1"
"线程 1":
  waiting to lock monitor 0x0000000002bf8708 (object 0x000000076bc2a1c8, a java.lang.Object),
  which is held by "线程 2"

Java stack information for the threads listed above:
===================================================
"??程 2":
        at JavaVM$2.run(JavaVM.java:47)
        - waiting to lock <0x000000076bc2a1b8> (a java.lang.Object)
        - locked <0x000000076bc2a1c8> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)
"线程 1":
        at JavaVM$1.run(JavaVM.java:29)
        - waiting to lock <0x000000076bc2a1c8> (a java.lang.Object)
        - locked <0x000000076bc2a1b8> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

 


JDK 可视化分析工具

JConsole:Java监视与管理控制台

它的主要功能是通过JMX的MBean对系统进行信息收集和参数动态调整。

通过JDK/bin目录下的jconsole.exe启动JConsole后,会自动搜索出本机运行的所有虚拟机进程。它可以对远程虚拟机进行监控

                                                                                         内存监控

jconsole可以显示当前内存的详细信息,包括堆内存,非堆内存,新生代,survior区等使用情况。

点击 “执行CG”按钮可以强制执行一个Full GC

 

                                                                                         线程监控

同样,jconsole可以做一次类似可视化的jstack命令的线程监控

 

VisualVM:多合-故障处理工具

它是一个运行监视和故障处理的程序,可以做到:

  • 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)。
  • 监视应用程序的 CPU、GC、堆、方法区以及线程的信息(jstat、jstack)。
  • dump 以及分析堆转储快照(jmap、jhat)。
  • 方法级的程序运行性能分析,找到被调用最多、运行时间最长的方法。

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章