一、基础故障处理工具
这里的基础主要指的是JDK中已经提供的命令,可以看下JDK安装包中的bin目录,其中包含了jps、jmap、jstat、jinfo、jhat、jstack等命令。
(一)jps:虚拟机进程状况工具
该命令主要用于显示目前运行的java进程,命令格式:jsp [options] [hostid]
可以跟随的命令如下所示:
选项 | 作用 |
-q | 只显示进程号,不显示类名等信息 |
-l | 显示进程号和类名,如果执行的是jar包,则显示jar包的路径 |
-m | 输出虚拟机进程启动时传递给主函数的参数 |
-v | 显示虚拟机启动时的参数 |
示例:
(二)jstat:虚拟机统计信息监视工具
该命令用于监控虚拟机各种运行状态信息,它可以显示本地或远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据,在没有GUI可视化界面、只有文本控制台的服务器上,它是运行期定位虚拟机问题的常用工具。
命令格式:jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
如果是远程服务器,则vmid为[protocol:][//]lvmid[@hostname[:port]/servername]
参数interval和count表示查询间隔和次数,如果省略了这两个参数,则说明只查询一次
option表示要查询的虚拟机信息,例如类加载、垃圾收集、运行期即时编译状况,具体参数如下所示:
选项 | 作用 |
-class |
显示类加载数量、加载总空间、卸载数量、卸载总空间及类装载所消耗的时间 |
-gc | 监视java堆状况,包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、垃圾收集时间合计等信息 |
-geccapatity | 监视内容基本与-gc一致,但输出主要关注java堆各个区域使用到的最大、最小空间 |
-gcutil | 监控内容基本与-gc一致,但是输出主要关注已使用空间占总空间的百分比 |
-gccause | 监控内容与-gcutil一致,但是输出为额外加上导致上一次gc的原因 |
-gcnew | 监视新生代垃圾回收情况 |
-gcnewcapaticy | 监视内容与-gcnew一致,但是会额外输出新生代使用的最大、最小空间 |
-gcold | 监视老年代的回收情况 |
-gcoldcapaticy | 监视内容与-gcold一致,但是会额外输出老年代使用的最大、最小空间 |
-gcpermcapaticy | 监控永久代使用的最大、最小空间 |
-compiler | 输出运行时即时编译器编译过的方法和耗时信息 |
-printcompilation | 输出已经被即时编译器编译的方法 |
以-gc命令为例:
结果表明:Eden(E)区使用率为96.33%,S0区和S1区使用率分别为0%和71.9%,老年代(O)使用率为22.35%,元空间(M)使用率为93.84%,压缩类空间(CCS)使用率为92.75%,新生代GC次数161次,新生代GC时间0.701秒,Full GC3次,时间为0.189秒,所有GC秒数为0.889秒。
(三)jinfo:java配置信息工具
jinfo命令用来实时查看和调整虚拟机各项参数。
命令格式:jinfo [option] <pid>
option可以是 -flag,表示要查看的内容,flag可以用java -XX:+PrintFlagsFinal来查看全量的标识。sysprops可以把虚拟机的所有配置文件打印出来。
命令样例:
(四)jmap:java内存映像工具
jmap命令用于堆转储快照,如果不使用该命令,也可以使用一些暴力手段,例如使用-XX:+HeapDumpOutOfMemoryError参数,通过该参数,可以让虚拟机在内存溢出时自动生成堆转储快照文件,也可以通过-XX:HeapDumpOnCtrlBreak参数并使用Ctrl+Break键生成堆转快照文件,也可以在linux系统下使用kill -3命令让虚拟机生成堆转快照文件。
命令格式:jmap [option] <pid>
jmap的option除了使用dump来处理堆转快照外,还提供了其他的一些命令,具体如下所示:
命令 | 说明 |
-dump | 堆转快照,格式为-dump:[live]format=b,file=<filename>,其中live子参数说明是否只dump出存活的对象 |
-finalizerinfo | 显示在F-Queue中等待finalizer线程执行finalize方法的对象,该命令只在linux和Solaris平台有效 |
-heap | 显示java堆详细信息,如使用哪种回收器、参数配置、分代状况等,只在linux和solaris平台有效 |
-histo | 显示堆中统计信息,包括类、实例数量、合计容量 |
-permstat | 以ClassLoader为统计口径显示永久代内存状态,只在linux和solaris平台有效 |
-F | 当虚拟机对-dump命令没有响应时,可通过该命令强制生成dump快照,只在linux和solaris平台有效 |
命令样例:
(五)jhat:堆转快照分析工具
jhat和jmap是对着使用的,jhat用以分析jmap生成的堆转快照文件,但是一般不这么用,一般会使用可视化工具查看。
使用jhat+快照文件命令后,出现already后即可使用
从上图可以看到端口号为7000,在浏览器访问local host:7000
可以看到分析结果是以包为单位进行分组显示的,分析内存泄漏问题是要会用到其中的Heap Histogram与OQL页签的功能,Heap Histogram可以找到内存中总容量最大的对象,OQL是标准的对象查询语言,使用类似SQL的语法进行查询。
(六)jstack:java堆栈跟踪工具
jstack命令用于生成虚拟机当前时刻的线程快照,线程快照是当前虚拟机每一条线程正在执行的方法堆栈的集合。
生成堆栈快照的目的一般是用来定位线程长时间停顿的原因,例如死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的原因。
命令格式:jstack [ option ] vmid
option选项如下所示:
选项 | 作用 |
-F | 当正常的请求不被相应时,强制输出堆栈信息 |
-l | 除显示堆栈信息外,额外输出锁的附加信息 |
-m | 如果调用到本地方法的话,可以显示C/C++的堆栈信息 |
命令示例:
二、可视化故障处理工具
JDK中除了提供了大量的命令行工具外,还提供了JConsole、JHSDB、VisualVM、和JMC四个可视化工具。
(一)JHSDB:基于服务性代理的调试工具
JDK中提供了JHSDB和JCMD两个集成式的多功能工具箱,他们不仅整合了上面所有基础工具所提供的功能,并且还比其做的要好。
代码示例:
public class DemoTest { 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 DemoTest.Test(); test.foo(); } }
JVM运行参数:-Xmx10m -XX:+UseSerialGC -XX:-UseCompressedOops
使用方法:
使用jps查看进程号,然后使用:jhsdb hsdb --pid 进程号 即可
(二)JConsole:JAVA监视与管理控制台
1、概述
JConsole主要功能是对系统进行信息收集和参数动态调整。可以通过JDK/bin目录中的jconsole.exe启动,启动后就可以看到本地运行的所有java进程,同时也可以访问远程的Java进程。
先写一个测试代码:
public class DemoTest1 { public static void main(String[] args) throws Exception {fillHeap(1000);} static class OOMObject{public byte[] placeholder = new byte[64 * 1024];} private static void fillHeap(int num) throws Exception { List<OOMObject> list = new ArrayList<>(); for (int i=0;i< num;i++){ Thread.sleep(50); list.add(new OOMObject()); } System.gc(); } }
启动后jconsole.exe后,可以看到相关进程,点击进入,可以看到系统运行的情况。
从上图可以看到,监控台有概述、内存、线程、类、VM摘要、MBean供6个选项,其中概述里面显示的是整个虚拟机主要运行数据的概要信息,包括堆的使用情况、线程、类、CPU使用情况的曲线图。
2、内存监控(类似jstat命令)
上述的代码示例就是用来做内存监控的,代码的含义是以64KB/50MS的速度向JAVA堆中填充数据,总共填充一千次。
在内存页可以看各个分代及整个堆空间的使用情况
3、线程监控(类似jstack命令)
代码演示:
public class DemoTest2 { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br.readLine(); createBusyThread(); br.readLine(); Object obj = new Object(); createLockThread(obj); } private static void createLockThread(Object obj) { Thread thread = new Thread(new Runnable() { @Override public void run() { synchronized (obj){ try{ obj.wait(); }catch (Exception e){ e.printStackTrace(); } } } }, "testLockThread"); thread.start(); } private static void createBusyThread() { Thread thread = new Thread(new Runnable() { @Override public void run() { while (true); } }, "testBusyThread"); thread.start(); } }
查看各个线程,就可以看到线程的运行情况。
(三)VisualVM:多合-故障处理工具
1、概要
VisualVM是功能最强大的运行监控和故障处理程序之一,他除了常规的运行监视、故障处理外,还将提供其他方面的能力,譬如性能分析等。
VisualVM兼容范围与插件安装
VisualVM基于NetBeans平台开发工具,所以其具备通过插件扩展功能的能力,有了插件的支持,VisualVM可以做到:
显示虚拟机进程以及进程的配置、配置信息(jps、jinfo)
监视应用程序的处理器、垃圾收集、堆、方法区、以及线程的信息(jstack、jstat)
dump堆转快照分析(jmap、jhat)
方法级的性能分析,找出被调用最多、执行时间最长的方法
离线程序快照:收集程序运行时配置、线程dump、内存dump、等信息建立一个快照,可以将快照发送给开发者进行分析
其他插件带来的其他功能
打开JDK下bin目录中的jvisualvm.exe,即可打开。
VisualVM可以安装许多插件,在打开的软件中选择“工具-插件”,然后在可用插件中即可查看可用的插件。
从下图可以看到,在VisualVM中,有概述、监视、线程、抽样器、Profiler等内容,其中概述、监视、线程等与JConsole差别不大。
2、生成、浏览堆转储快照
在左侧的java进程上,可以选择生成线程Dump和堆Dump,然后就可以对线程或堆进行分析。
摘要:可以看到程序dump时的运行参数、环境参数线程堆栈等信息;
类:以类为统计口径进行统计类的实例数量、容量信息;
实例数:不可以直接进入,需要从类中选择具体的类进入
OQL:运行OQL查询语句,与jhat中的OQL功能一样。
3、Profiler:分析程序性能
在Profiler页签中,VisualVM提供了程序运行期间方法级的处理执行时间分析以及内存分析,但是做Profiling分析肯定会对程序运行性能有比较大的影响,所以一般不会在生产环境中使用,如果想要使用,可以改为下面的JMC来完成,JMC的Profiling能力更强,对应用的影响非常轻微。
4、BTrace动态日志跟踪
其作用是在不中断目标程序运行的前提下,通过Hotspot虚拟机的Instrument功能动态加入原本并不存在的调试代码。
我这里在线安装时,显示网络问题,所以选个手动离线安装,访问:https://visualvm.github.io/uc/8u131/updates.html,选择BTrace Workbench,下载完毕后,在“工具-插件”已下载中选择下载的插件
下面是样例代码:
public class DemoTest3 { public static void main(String[] args) throws Exception { for (int i=0; i< 10000; i++){ Thread.sleep(500); int a = (int) Math.round(Math.random() * 1000); int b = (int) Math.round(Math.random() * 1000); System.out.println("=================" + add(a,b)); } } public static int add(int a, int b){ return a+b; } }
然后在VisualVM中选中DemoTest3进程,右键选择Trance Application,就会出现Trance的界面,在Trance界面中编写测试代码
import com.sun.btrace.annotations.*; import static com.sun.btrace.BTraceUtils.*; @BTrace public class TracingScript { @OnMethod(clazz="com.lcl.jdk8emo.DemoTest3",method="add",location=@Location(Kind.RETURN)) public static void func(@Self com.lcl.jdk8emo.DemoTest3 instance,int a,int b,@Return int result){ println("调用堆栈:"); jstack(); println(strcat("方法参数a:", str(a))); println(strcat("方法参数b:", str(b))); println(strcat("结果:", str(result))); } }
在测试程序启动后,点击start,即可实时查看程序运行结果:
BTrace的用途很广泛,打印调用堆栈、参数、返回值只是它最基础的使用形式,其还可以进行性能监控、定位连接泄露、内存泄漏、解决多线程竞争问题等的使用案例。
阿里开源的诊断工具Arthas也是通过Instrument实现了与BTrace类似的功能
(四)Java Mission Control:可持续在线的监控工具
点击JDK/bin目录下的JMC.exe文件,会显示本地运行的java进程,也可以在“JVM浏览器”页右键创建远程连接,连接后,操作内容与本地一样。
点开JVM浏览器可以看到,每个进程的数据都有MBean和JFR两个数据来源。
1、MBean
MBean这部分数据与JConsole和VisualVM上取到的内容是一样的,只是展示内容有所不同。
2、JFR
双击飞行记录器,如果提示没有开启,则需要对其进行开启(开启飞行器:-XX:+UnlockCommercialFeatures -XX:+FlightRecorder)。
双击后点击完成,则会进行飞行记录,可以进行记录时间、垃圾收集器、编译器、方法采样、线程记录、异常记录、网络和文件IO、事件记录等选项和频率设定。其基本的工作逻辑是开启一系列事件的录制动作,当某个事件发生时,这个事件的所有上下文数据将会以循环日志的形式被保存至内存或者指定的某个文件当中,循环日志相当于数据流被保留在一个环形缓存中,所以只有最近发生的事件的数据才是可用的。JMC从虚拟机内存或者文件中读取并展示这些事件数据,并通过这些数据进行性能分析。
飞行记录报告里包含以下几类信息:
一般信息:关于虚拟机、操作系统和记录的一般信息
内存:关于内存管理和垃圾收集的信息
代码:关于方法、异常错误、编译和类加载信息
线程:关于应用程序中线程和锁的信息
IO:关于文件和套接字输入输出的信息
系统:关于正在运行java虚拟机的系统、进程和环境变量的信息
事件:关于记录中的事件类型信息,可以根据线程或堆栈跟踪,按照日志或图形的格式查看。