6.虚拟机性能监控与故障处理工具

本文详细介绍了JDK自带的虚拟机监控和故障处理命令行工具,包括jps、jstat、jinfo、jmap、jhat、jstack的使用方法和功能。这些工具可以帮助开发者监测Java进程状态、收集运行数据、分析内存和线程问题,提高问题定位效率。此外,文章还提及了JConsole和VisualVM两款可视化监控工具,它们提供了更直观的内存和线程监控方式,尤其在处理死锁和性能瓶颈时非常有用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、虚拟机命令行工具
1.虚拟机工具概述
概述:给一个系统定位问题的时候,知识、经验是关键基础,数据是依据,工具是运用知识处理数据的手段。这里说的数据包括:运行日志、异常堆栈、GC日志、线程快照(threaddump/javacore文件)、堆转储快照(heapdump/hprof文件)等。经常使用适当的虚拟机监控和分析的工具可以加快我们分析数据、定位解决问题的速度,但在学习工具前,也应当意识到工具永远都是知识技能的一层包装,没有什么工具是“秘密武器”,不可能学会了就能包治百病。

JDK的命令行工具:Java开发人员肯定都知道JDK的bin目录中有“java.exe”、“javac.exe”这两个命令行工具,但并非所有程序员都了解过JDK的bin目录之中其他命令行程序的作用。每逢JDK更新版本之时,bin目录下命令行工具的数量和功能总会不知不觉地增加和增强。书中主要介绍:这些工具的其中一部分,主要包括用于监视虚拟机和故障处理的工具。这些故障处理工具被Sun公司作为“礼物”附赠给JDK的使用者,但事实上,这些工具都非常稳定而且功能强大,能在处理应用程序性能问题、定位故障时发挥很大的作用。
在这里插入图片描述

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

2.jps:虚拟机进程状况工具
主要功能:可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。对于本地虚拟机进程来说,LVMID与操作系统的进程ID(Process Identifier,PID)是一致的,使用Windows的任务管理器或者UNIX的ps命
令也可以查询到虚拟机进程的LVMID。不带任何参数的命令如下:
在这里插入图片描述
命令格式
在这里插入图片描述
jps工具主要选项
在这里插入图片描述
jps -q 示例:
在这里插入图片描述
jps -m 示例:
在这里插入图片描述
jps -l 示例:
在这里插入图片描述
jps -v 示例:
在这里插入图片描述

3.jstat:虚拟机统计信息监视工具
主要功能:是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程[1]虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

命令格式
在这里插入图片描述
:对于命令格式中的VMID与LVMID需要特别说明一下:如果是本地虚拟机进程,VMID与LVMID是一致的,如果是远程虚拟机进程,那VMID的格式应当是:
在这里插入图片描述
jstat工具主要选项
在这里插入图片描述
示例:由于jstat 命令需要指定进程号,所以依赖于jps进程命令,
在这里插入图片描述
参数interval和count代表查询间隔和次数,如果省略这两个参数,说明只查询一次。假设需要每250毫秒查询一次进程8328垃圾收集状况,一共查询10次,那命令应当是::
jstat -gcutil 8328 250 10
在这里插入图片描述
结果分析
查询结果表明:这台服务器的新生代Eden区(E,表示Eden)使用了6%的内存空间,两个Survivor区(S0、S1,表示Survivor0、Survivor1)里面都是空的,老年代(O,表示Old)使用0%空间,元空间(M)使用了0%的空间。程序运行以来共发生Minor GC(YGC,表示Young GC)0次,总耗时(YGCT)0秒,发生Full GC(FGC,表示FullGC)0次,Full GC总耗时(FGCT,表示Full GC Time)为00秒,所有GC总耗时(GCT,表示GC Time)为0秒(应为YGCT和FGCT之和)。

具体功能选项可参考官网:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

4.jinfo:Java配置信息工具
主要功能:实时地查看和调整虚拟机各项参数。使用jps命令的-v参数可以查看虚拟机启动时显式指定的参数列表,但如果想知道未被显式指定的参数的系统默认值,除了去找资料外,就只能使用jinfo的-flag选项进行查询了。

命令格式
在这里插入图片描述

利用jinfo -help命令查看命令选项
在这里插入图片描述

使用举例:查看Eclipse进程是否使用Serial GC 或者 G1 GC ,出现-XX:+UseG1GC,代表使用G1垃圾收集器
在这里插入图片描述

5.jmap:Java内存映像工具
主要功能:jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)。jmap的作用并不仅仅是为了获取dump文件,它还可以查询finalize执行队列、Java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。

命令格式
在这里插入图片描述
jmap主要命令选项
在这里插入图片描述
使用举例:使用-dump选项,在d盘下生成a.bin文件。
在这里插入图片描述

注意:jmap和jinfo命令的不少功能在Windows平台下都是受限的,除了生成dump文件的-dump选项和用于查看每个类的实例、空间占用统计的-histo选项在所有操作系统都提供之外,其余选项都只能在Linux/Solaris下使用。

6.jhat:虚拟机堆转储快照分析工具
主要功能:Sun JDK提供jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照。jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,可以在浏览器中查看。

一般都不会去直接使用jhat命令来分析dump文件:主要因为:1)在服务器上直接用命令行工具分析dump文件会十分占用内存和CPU资源;2)jhat的分析功能相对来说比较简陋,后文将会介绍到的VisualVM,以及专业用于分析dump文件的Eclipse MemoryAnalyzer、IBM HeapAnalyzer[2]等工具。

7.jstack:Java堆栈跟踪工具
主要功能:jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情,或者等待着什么资源。

命令格式
在这里插入图片描述
命令工具主要选项
在这里插入图片描述
另注:在JDK 1.5中,java.lang.Thread类新增了一个getAllStackTraces()方法用于获取虚拟机中所有线程的StackTraceElement对象。使用这个方法可以通过简单的几行代码就完成jstack的大部分功能,在实际项目中不妨调用这个方法做个管理员页面,可以随时使用浏览器来查看线程堆栈,如代码清单4-5所示,这是作者的一个小经验,测试代码如下:

public class test{
	public static void main(String[] args) {
        Map<Thread,StackTraceElement[]> m = Thread.getAllStackTraces();
        for(Map.Entry<Thread, StackTraceElement[]> en : m.entrySet()) {
        	Thread t = en.getKey();
        	StackTraceElement[] v = en.getValue();
        	
        	System.out.println("Thread name is:" + t.getName());
        	for(StackTraceElement s : v) {
        		System.out.println("\t" + s.toString());
        	}
        }
	}
}

运行结果
在这里插入图片描述
二、虚拟机可视化工具
1.JConsole:Java监视与管理控制台
启动:直接点击JDK中bin目录下的jconsole.exe启动。双击选择其中一个进程即可开始监控,可以是本地进程,也可以使用下面的“远程进程”功能来连接远程服务器,对远程虚拟机进行监控。

1.内存监控:
概述:“内存”页签相当于可视化的jstat命令,用于监视受收集器管理的虚拟机内存(Java堆和元空间)的变化趋势。我们通过运行代码清单4-8中的代码来体验一下它的监视功能。运行时设置的虚拟机参数为:-Xms100m -Xmx100m -XX:+UseSerialGC,这段代码的作用是以64KB/50毫秒的速度往Java堆中填充数据,一共填充1000次,使用JConsole的“内存”页签进行监视,观察曲线和柱状指示图的变化。

测试代码

public class test{
	static class OOMObject{
		public byte[] placeholder = new byte[128*1024];  //内存占位符,一个对象占128KB
	}
	
	public static void fillHeap(int num) throws InterruptedException{
		List<OOMObject> list = new ArrayList<OOMObject>();
		for(int i=0; i < num; i++) {
			Thread.sleep(100);     //每次创建对象间隔100ms
			list.add(new OOMObject());
		}
		System.gc();
	}
	
	public static void main(String[] args) throws Exception{ 
		Thread.sleep(5000);   //执行之前等待5s,为了便于我们手动打开JConsole
		fillHeap(1000);
	}
}

堆内存-Eden区:Eden区域是垃圾收集器最喜欢光顾的区域,所以其上升到一定程度(这里门限是40M)后,就会被垃圾回收器回收,放到Survivor或者老年代中,到最后程序调用System.gc(),在Eden区域达到20多M的时候就被回收。
在这里插入图片描述
堆内存-Old gen区:堆内存中的老年代占用内存不断上升,因为Eden或者Survivor区域中的对象经过垃圾回收器回收后不断放到老年代中,最后程序终止运行,老年代也被回收
在这里插入图片描述
堆内存-Survivor区:该区域先增加后变为0,因为到最后都进入老年代了。

2.线程监控:
概述:如果上面的“内存”页签相当于可视化的jstat命令的话,“线程”页签的功能相当于可视化的jstack命令,遇到线程停顿时可以使用这个页签进行监控分析。前面讲解jstack命令的时候提到过线程长时间停顿的主要原因主要有:等待外部资源(数据库连接、网络资源、设备资源等)、死循环、锁等待(活锁和死锁)。

线程“死循环”演示:写一个while死循环,结果显示,程序一直处于运行状态(即Runnable状态),并且一直在11行代码处运行。
测试代码:

public class test{
	public static void main(String[] args) throws Exception{ 
        Thread thread1 = new Thread(new Runnable(){
            @Override
        	public void run() {
        		while(true) {}
        	}        	
        },"while_true");
        thread1.start();
	}
}

演示结果:
在这里插入图片描述
线程等待演示:创建的线程thread2后,运行run()方法,之后进入等待状态,等待数为1,等待被唤醒。
测试代码:

public class test{
	public static void main(String[] args) throws Exception{ 
        testwait(new Object());
	}
	
	public static void testwait(Object obj) {
        Thread thread2 = new Thread(new Runnable(){

            @Override
        	public void run() {
            	synchronized(obj){
            		try {
            			obj.wait();
            		}
            		catch(InterruptedException e) {
            			e.printStackTrace();
            		}
            	}
        	}        	
        },"wait");
        thread2.start();
	}
}

演示结果:
在这里插入图片描述

3.死锁监控:
“死锁”的概念:两个线程相互等待的过程,从而导致程序一直在运行。举例:创建Object对象obj1和obj2,创建两个线程,同时去分别访问obj1、obj2和obj2、obj1,若线程1占用了obj1,下一步即将占用obj2,此时线程2占用了obj2,下一步即将占用obj1,此时,线程1在等待线程2释放obj2,而线程2在等待线程1释放obj1,则出现“死循环”,称之为“线程死锁”。

:“synchronized”关键词的作用是确保在某个时刻只有一个线程被允许执行特定的代码块。

测试代码

public class DeadLock implements Runnable {
    private Object obj1;
    private Object obj2;
    
    public DeadLock(Object obj1,Object obj2) {
    	this.obj1 = obj1;
    	this.obj2 = obj2;
    }
    
    @Override
    public void run() {
    	synchronized(obj1) {
    		try {
				Thread.sleep(10);   //线程访问第一个参数obj1后等待100ms,此时则会产生死锁
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		synchronized(obj2) {
    			System.out.println("hello");
    		}
    	}
    }
}
public class test{
	public static void main(String[] args){ 
        Object obj1 = new Object();
        Object obj2 = new Object();
        
        new Thread(new DeadLock(obj1,obj2)).start();
        new Thread(new DeadLock(obj2,obj1)).start();     
	}
}

运行结果
在这里插入图片描述

结果分析:结果显示,在JConsole中点击“死锁检测”按钮,会出现两个死锁的进程,相互等待。创建了两个匿名线程对象(线程1和线程2),两个线程几乎同时执行,线程1利用test类中的obj1和obj2为构造参数,创建了DeadLock类对象,所以DeadLock类中的obj1和obj2分别指向test类中的obj1和obj2,然后执行run()方法,synchronized(obj1)执行时,说明此时test中的obj1被占用,此时延迟10ms,同时线程2也执行相同步骤,不过线程2占用的是test类中的obj2,并等待10ms,10ms之后,两个线程相互等待对方释放资源,从而执行synchronized(obj2)代码块,但是两块内存都被双方占用,也都不会释放,所以形成“死锁”。

2.VisualVM:多合一故障处理工具
概述:VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,并且可以预见在未来一段时间内都是官方主力发展的虚拟机故障处理工具。

操作界面
在这里插入图片描述
:VisualVM是基于插件的一款分析工具,后续根据需要,安装相应的插件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值