其他分享
首页 > 其他分享> > JDK性能监控工具

JDK性能监控工具

作者:互联网

实战java虚拟机


JDK性能监控工具

jdk开发包中,除了比较熟悉的java.exe,javac.exe,还有一系列的辅助工具,它们都存放在jdk安装目录/bin目录下,乍一看这些都是exe,但实际上它们只是将java程序的一层包装,真正的实现是在lib/tools.jar中。以jps命令为例,它实质上是运行:

java -classpath $JAVA_HOME/lib/tools.jar sun.tools.jps.Jps
  • 1

查看Java进程——jps命令

jps类似于ps命令,不同的是它只列出系统中所有java应用程序,jps命令格式
jps [-q] [-mlvV] [<hostid>]

查看虚拟机运行时信息——jstat命令

jstat用于观察java应用程序运行时相关信息的工具。它的功能特别,它的基本语法:
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]


-class

Loaded  Bytes  Unloaded  Bytes     Time
  1546  2835.7        0     0.0       2.06
//loaded 载入类的数量
//Bytes 载入类的合计大小
//Unloaded  卸载类的数量
//第二个bytes 卸载类的合计大小
//time 加载和卸载的时间之和
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

-compiler

Compiled Failed Invalid   Time   FailedType FailedMethod
     847      0       0     1.28          0
//Compiled 编译任务执行的次数,
//Failed 编译失败的次数,
//Invalid 编译不可用次数
//FailedType 最后一次失败的类型
//FailedMethod 最后一次失败的类名和方法名
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

-gc

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
5120.0 5120.0 2208.0  0.0   63488.0  54658.8   84992.0      24.0    8832.0 8388.6 1152.0 984.5       4    0.021   0      0.000    0.021

//S01,S1C,S0U,S1U from,to的大小和已用量大小(KB)
//EC,EU eden的大小和已用量
//OC,OU 老边代的大小和已用量
//PC,PM 永久区大小和已用量
— JDK8之后变为
// MC,MU ,元数据区大小和已用量
//CCSC,CCSU 压缩类空间大小和已用量

//YGC,YGCT: 新生代GC次数和耗时
//FGC,FGCT: Full GC次数和耗时
//GCT GC总耗时


-gccapacity

 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC
 41984.0 673792.0  73728.0 5120.0 5120.0  63488.0    84992.0  1347584.0    84992.0    84992.0      0.0 1056768.0   8832.0      0.0 1048576.0   1152.0      4     0
//NGCMN ,NGCMX : 新生代最小值和最大值(KB)
//MN:表示最小 ,MX表示最大
  • 1
  • 2
  • 3
  • 4

-gccause

  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC
 42.81   0.00  86.20   0.05  95.00  85.50      4    0.018     0    0.000    0.018 Allocation Failure   No GC

//LGCC 上次GC原因
//GCC 本次GC原因


-gcnew

 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT
5120.0 5120.0 2208.0    0.0  7  15 5120.0  63488.0  54658.8      4    0.021

//TT 新生代晋升到老年代年龄
//MTT 新生代晋升到老年代最大年龄
//DSS 所需的survivor区大小


查看虚拟机参数——jinfo命令

jinfo可以用来查看正在运行的java应用程序的扩展参数,甚至支持在运行时,修改部分参数,它的基本语法为:jinfo [option] <pid>
它的option值可以为:

- flags : 如-XX:NewSize,-XX:OldSize等虚拟机相关参数.
- sysprops :java.class.path,java.vm.info等…

这里写图片描述


导出堆到文件——jmap命令

jmap命令是一个多功能命令。它可以生成Java程序的堆Dump文件,也可以查看堆内对象实例的统计信息、查看ClassLoader的信息以及finalizer队列。它的命令格式:

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)

option选项有如下:


-histo
统计9336号进程的存活对象统计信息,并保存到文件:$ jmap -histo:live 9336 >d:/dum02.txt,结果如下图:
这里写图片描述
,结果中统计了内存中实例对象数和合计。

-dump
-dump功能得到java程序的当前堆快照:jmap -dump:format=b,file=d:/heamp.hprof 8996

-clstats 与 permstat
该命令还可以查看系统的classloader信息,以及classloader的父子关系,以及各个classloader内部加载的类的数量和总大小。$ jmap -clstats 7876
这里写图片描述

-finalizerinfo
可以观察系统中finalizer队列中的对象,一个不恰当的finalize()方法可能导致对象堆积在finalizer队列里。$ jmap -finalizerinfo 7876
这里写图片描述
,上图的finalizer队列长度为0。


JDK自带的堆分析工具——jhat

使用jhat工具可以分析java应用程序的堆快照内容:$ jhat d:/heap.hprof
这里写图片描述


查看线程堆栈信息——jstack

jstack可以打印出java程序的线程堆栈信息。jstack [option] <pid>

option选项信息:

下例为一个死锁程序,java程序代码如下:

public class DeadLock extends Thread{
	protected Object myDirect;
	static ReentrantLock south = new ReentrantLock();
	static ReentrantLock north = new ReentrantLock();
public DeadLock(Object obj) {
	this.myDirect = obj;
	if(myDirect == south) {
		this.setName("south");
	}
	if(myDirect == north) {
		this.setName("north");
	}
}

@Override
public void run() {
	if(myDirect == south) {
		try {
			north.lockInterruptibly();
			Thread.sleep(500);
			south.lockInterruptibly();
			System.out.println("car to south has passed");
		} catch (InterruptedException e) {
			e.printStackTrace();
			System.out.println("car to south is killed");
		} finally {
			if(north.isHeldByCurrentThread()) {
				north.unlock();
			}
			if(south.isHeldByCurrentThread()) {
				south.unlock();
			}
		}
		
	}
	if(myDirect == north) {
		try {
			south.lockInterruptibly();
			Thread.sleep(500);
			north.lockInterruptibly();
			System.out.println("car to north has passed");
		} catch (InterruptedException e) {
			e.printStackTrace();
			System.out.println("car to north is killed");
		} finally {
			if(south.isHeldByCurrentThread()) {
				south.unlock();
			}
			if(north.isHeldByCurrentThread()) {
				north.unlock();
			}
		}
	}
}

public static void main(String[] args) throws InterruptedException {
	DeadLock car2south = new DeadLock(south);
	DeadLock car2north = new DeadLock(north);
	car2south.start();
	car2north.start();
	Thread.sleep(1000);
}

}

使用命令jstak -l pid >d:/dead.txt 打印结果:

"north" prio=6 tid=0x00000000069ad000 nid=0x2bcc waiting on condition [0x000000000792f000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000007d6e54508> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:867)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1201)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312)
	at cn.jhs.chap05.DeadLock.run(DeadLock.java:50)

Locked ownable synchronizers:
- <0x00000007d6e544d8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

“south” prio=6 tid=0x000000000699c800 nid=0x1ed0 waiting on condition [0x000000000782f000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007d6e544d8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:867)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1201)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312)
at cn.jhs.chap05.DeadLock.run(DeadLock.java:31)

Locked ownable synchronizers:
- <0x00000007d6e54508> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
//省略输出。。。。。
Found one Java-level deadlock:

“north”:
waiting for ownable synchronizer 0x00000007d6e54508, (a java.util.concurrent.locks.ReentrantLockNonfairSync),whichisheldby"south""south":waitingforownablesynchronizer0x00000007d6e544d8,(ajava.util.concurrent.locks.ReentrantLockNonfairSync), which is held by "south" "south": waiting for ownable synchronizer 0x00000007d6e544d8, (a java.util.concurrent.locks.ReentrantLockNonfairSync),whichisheldby"south""south":waitingforownablesynchronizer0x00000007d6e544d8,(ajava.util.concurrent.locks.ReentrantLockNonfairSync),
which is held by “north”

Java stack information for the threads listed above:

//省略输出。。。。。
Found 1 deadlock.


远程主机——jstat

一些监控工具支持远程计算机的控制(如jps,jstat),为了开启远程监控,则需要配合使用jstatd工具。
命令jstatd则是一个RMI服务端程序,它的作用相当于对代理服务器,建立本地计算机与远程监控工具的通信。jstatd服务器将本机的java应用程序传递到远程计算机。如图:
这里写图片描述

它的命令格式:usage: jstatd [-nr] [-p port] [-n rminame]
option选项:

直接运行jstatd命令会报错,这是因为没有足够的权限所致。可以使用java的安全策略,为其分配相应的权限,并命名为all.policy

grant codebase "file:${JAVA_HOME}\lib\tools.jar" {
    permission java.security.AllPermission;
};
  • 1
  • 2
  • 3

使用命令:jstatd -J-Djava.security.policy=all.policy 服务即开启,默认端口1099。jstatd更为详尽的配置
使用jsp.jstat命令即可访问远程服务器的信息。

jps localhost:1099;

jstat -gcutil 460@localhost:1099 //----460为进程号


多功能命令行——jcmd命令

在jdk1.7之后,新增了一个命令行工具jcmd,它是一个多功能工具,用它可以导出堆,查看java进程,导出线程信息,执行GC等。
使用命令:jcmd -l 列出本机所有的虚拟机。
针对每一个虚拟机可以使用:jcmd pid help来列出pid对应虚拟机所支持的命令。
然后挑选出虚拟机支持的任意命令执行:jcmd pid choosed_vm_cmd;
这里写图片描述

也可是使用:jcmd Mainclass来替代jcmd pid;

虚拟机信息如下:
9196 org.jetbrains.idea.maven.server.RemoteMavenServer
======================================================
$ jcmd 9196 help
等价于
$ jcmd org.jetbrains.idea.maven.server.RemoteMavenServer help
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

jcmd拥有jmap大部分功能,并且Oracle官方也推荐使用jcmd替代jmap.


性能统计工具——hprof

HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)
与之前的监控工具不同,hprof不是独立的监控工具,它是一个java agent工具。它可以用于监控java应用程序在运行时的CPU和堆信息。使用java agentlib:hprof=help命令可以查看hprof的帮助文档。

Option Name and Value  Description                    Default
---------------------  -----------                    -------
heap=dump|sites|all    heap profiling                 all
cpu=samples|times|old  CPU usage                      off
monitor=y|n            monitor contention             n
format=a|b             text(txt) or binary output     a
file=<file>            write data to file             java.hprof[{.txt}]
net=<host>:<port>      send data over a socket        off
depth=<size>           stack trace depth              4
interval=<ms>          sample interval in ms          10
cutoff=<value>         output cutoff point            0.0001
lineno=y|n             line number in traces?         y
thread=y|n             thread in traces?              n
doe=y|n                dump on exit?                  y
msa=y|n                Solaris micro state accounting n
force=y|n              force output to <file>         y
verbose=y|n            print messages about dumps     y

图形化虚拟机监控工具JConsole

JConsole是JDK自带的图形化性能监控工具,通过它可以监控堆信息、永久区信息、类加载信息、线程信息、JVM信息等。
连接JAVA程序
JConsole在JAVA_HOME/bin目录下,启动后,会出现新建连接对话框,可以连接本地应用程序,也可以连接远程程序。针对远程程序,需要远程程序在启动时,增加如下参数:

-Djava.rmi.server.hostname=127.0.0.1   //---ipv4地址是:192.1.217.111
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8889
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
  • 1
  • 2
  • 3
  • 4
  • 5

然后在监控端启动JConsole,选择远程连接:
这里写图片描述


可视化性能监控工具Visual VM

visual vm是一个功能强大的多合一的故障诊断和性能监控的可视化工具,使用visual vm可以代替jstat,jmap,jhat,jstack甚至替代jconsole.
使用命令:jvisualvm启动Visual VM.

连接应用程序
Visual VM支持多种方式连接应用程序:

监控应用程序
选中了应用程序之后,即可看到监控的页面如下图:
这里写图片描述

Visual VM 的 BTrace插件(略)
BTrace是一款非常有意思的工具,它可以在不停机的情况下,通过字节码注入动态的监控系统的运行情况,它可以跟踪方法的调用,构造函数调用和系统内存等信息。


虚拟机诊断工具Mission Control

在Oracle收购sun之前,Oracle的JRockit虚拟机提供了一款JRockit Mission Control的虚拟机诊断工具。在收购sun之后,Oracle拥有了Sun Hotspot 和JRockit两款虚拟机,根据Oracle的战略,在JDK7 Update 40之后,将MissionControl集成到了Hotspot中。它位于$JAVA_HOME/bin/jmc.exe.

MBean服务器
这里写图片描述

飞行记录器(Flight Recorder)
它通过记录程序在一段时间内的运行情况,将记录结果进行分析和展示,可以进一步对系统的性能进行分析和诊断。要使用飞行记录器,对于要监控的程序必须添加参数:

-XX:+UnlockCommercialFeatures -XX:+FlightRecorder 
  • 1

这里写图片描述

标签:java,JDK,虚拟机,信息,util,locks,监控,性能,south
来源: https://blog.csdn.net/weixin_41427294/article/details/123591227