JDK监控和故障处理工具
JDK的bin目录下有许多命令行工具,他们大多数是在tools类库实现的,借助这些工具,我们可以直接在应用程序中实现功能强大的监控分析功能。
监控和故障处理工具如下表所示:
名称 | 主要作用 |
---|---|
jps | JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。 |
jstat | JVM Statistics Monitoring Tool,用于收集HotSpot虚拟机各方面的运行数据 |
jinfo | Configuration Info forJava,显示虚拟机配置信息 |
jmap | Memory Map for Java,生成虚拟机的内存转储快照(HeapDump文件) |
jhat | JVM Heap Dump Browser,用于分析HeapDump文件,它会建立一个HTTP/HTML服务器,让用户可以在浏览器上查看分析结果 |
jstack | Stack Trace for Java,显示虚拟机的线程快照 |
jps虚拟机进程状况工具
jps与UNIX的ps类似,可以列出正在运行的虚拟机进程,并显示虚拟机执行主类名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier, LVMID),jps还可以通过RMI协议查询开启了RMI服务的远程虚拟机进程状态。具体命令如下:
选项 | 作用 |
---|---|
-q | 只输出LVMID,省略主类名称 |
-m | 输出虚拟机进程启动时传递给主类main()函数的参数 |
-l | 输出主类的全名,如果进程执行的是Jar包,输出Jar路径 |
-v | 输出虚拟机进程启动时JVM参数 |
jstat:虚拟机统计信息监视工具
jstat是用于监视虚拟机各种运行状态信息的命令行工具,它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
jstat命令格式为:jstat [option vmid [interval[s|ms]] [count]]
每250ms查询一次进程2764垃圾收集情况,查询20次的命令就是:
jstat -gc 2764 250 20
interval代表查询间隔,count代表次数,省略这两个参数,说明只查询一次。option代表用户希望查询的虚拟机信息,主要分为3类:类装载、垃圾收集、运行期编译状况。主要选项如下表所示:
选项 | 作用 |
---|---|
-class | 监视类装载、卸载数量、总空间以及类装载所耗费的时间 |
-gc | 监视Java堆状况,包括Eden区、两个Survivor区、老年代等的容量、已用空间、GC时间合计等信息 |
-gccapacity | 与-gc基本相同,主要关注Java堆各个区域使用到的最大最小空间 |
-gcutil | 与-gc基本相同,主要关注已使用空间占总空间的百分比 |
-gccause | 与-gcutil功能一样,额外输出导致上一次gc产生的原因 |
-gcnew | 监视新生代gc状况 |
-gcnewcapacity | 与-gcnew基本相同,主要关注使用到的最大、最小空间 |
-gcold | 监视老年代GC状况 |
-gcoldcapacity | 与-gcold基本相同,主要关注使用到的最大、最小空间 |
-compiler | 输出JIT编译器编译过的方法、耗时等信息 |
-printcompilation | 输出已经被JIT编译的方法 |
jinfo:Java配置信息工具
jinfo的作用是实时的查看和调整虚拟机各项参数,-flag命令未被显示指定的参数的系统默认值,-sysprops把虚拟机进程的System.getProperties()的内容打印出来。
jmap:Java内存映像工具
jmap命令用于生成堆转储快照,也可以设置虚拟机参数生成dump文件。jmap还可以查询finalize执行队列、Java堆的详细信息,如空间使用率、当前用的是哪种收集器等。Windows只能使用-dump选项和-histo选项。下面是主要选项:
选项 | 作用 |
---|---|
-dump | 生成Java堆转储快照,格式为-dump:[live,]format=b,file=,live说明只dump出活的对象 |
-finalizerinfo | 显示在F-Queue中等待Finalizer线程中执行finalize方法的对象 |
-heap | 显示Java堆详细信息,如使用哪种回收器、参数配置、分代状况等 |
-histo | 显示堆中对象统计信息,包括类、实例数量、合计容量 |
-F | 强制生成dump快照 |
jhat:虚拟机堆转储快照分析工具
jhat与jmap搭配,可分析dump出来的快照,可以用内存分析工具代替jhat如JProfiler、VisualVM等。
jstack:Java堆栈跟踪工具
jstack用于生成虚拟机当前时刻的线程快照,线程快照是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,可以知道没有响应的线程到底在后台做什么事情,或等待什么资源。主要选项如下:
选项 | 作用 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的附加信息 |
-m | 如果调用到本地方法的话,可以显示C/C++的堆栈 |
Thread类的getAllStackTraces()也可以实现jstack的大部分功能,生成的是一个map,键为线程,值为线程堆栈。
JDK可视化工具
JConsole:Java监视与管理控制台(Java Monitoring and Management Console)
JConsole是一种基于JMX的可视化监视管理工具,它对JMX MBean进行管理。下面是JConsole的运行界面:
概览一栏显示整个虚拟机主要运行数据,内存一栏相当他jstat,可以监视虚拟机内存的变化趋势,线程一栏相当于可视化的jstack,遇到线程停顿可以用它进行监控分析。下面是一些代码分析示例:
package toolstest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author Zhang
* @date 2018/8/18
* @Description
*/
public class ThreadTest {
public static void createBusyThread(){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true);
}
},"testBusyThread");
thread.start();
}
//线程锁等待演示
public static void createLockThread(final Object lock){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
try {
lock.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
},"testLockThread");
thread.start();
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();
createBusyThread();
br.readLine();
Object obj = new Object();
createLockThread(obj);
}
}
代码运行后,查看main线程,如下图,堆栈跟踪显示在等待System.in输入,状态为RUNNABLE。
接着执行testBusyThread线程,可以看到线程一直在执行18行的空循环:
执行testLockThread线程,可以看到它处于阻塞状态,等待被notifyAll方法唤醒:
一个死锁的执行测试:
package toolstest;
import java.util.concurrent.locks.Lock;
/**
* @author Zhang
* @date 2018/8/18
* @Description
*/
public class DeadLock {
public static String obj1 = "obj1";
public static String obj2 = "obj2";
public static void main(String[] args){
Thread a = new Thread(new Lock1());
Thread b = new Thread(new Lock2());
a.start();
b.start();
}
}
class Lock1 implements Runnable{
@Override
public void run(){
try{
System.out.println("Lock1 running");
while(true){
synchronized(DeadLock.obj1){
System.out.println("Lock1 lock obj1");
Thread.sleep(3000);//获取obj1后先等一会儿,让Lock2有足够的时间锁住obj2
synchronized(DeadLock.obj2){
System.out.println("Lock1 lock obj2");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
class Lock2 implements Runnable{
@Override
public void run(){
try{
System.out.println("Lock2 running");
while(true){
synchronized(DeadLock.obj2){
System.out.println("Lock2 lock obj2");
Thread.sleep(3000);
synchronized(DeadLock.obj1){
System.out.println("Lock2 lock obj1");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
如下图所示,可点击检测死锁监测到发生死锁的线程:
由图可知,两个线程互相等待释放锁,形成死锁。
VisualVM:多合一故障处理工具(All-in-One Java Troubleshooting Tool)
VisualVM具有运行监视、故障处理、性能分析等功能,甚至不比JProfiler逊色,而且不需要被监视的程序基于特殊Agent运行,因此它对应用程序的实际性能的影响很小。
通过插件扩展,可以实现以下功能:
- jps、jinfo的功能;
- jstat、jstack的功能;
- jmap、jhat的功能;
- 方法级程序分析;
- 离线程序快照等等。
安装插件,先在设置中修改插件地址,如下图所示,网址改为自己想要的版本地址,下载地址如下,选择版本复制地址即可:
然后点击可用插件选择自己要安装的插件,如图:
安装即可,运行界面如图所示,一般功能与JProfiler类似: