文章目录
一、JDK的命令行工具
JDK的 bin 目录下为我们提供了很多的工具,如在 Windows安装JDK及Maven 中使用的 java、javac ,以及在 类文件结构及字节码指令 中使用的 javap 等,其实bin目录下还为我们提供了很多的工具,包括了很多用于监视虚拟机性能和故障处理工的工具,如下:

这里可以启动如下代码,然后利用介绍的JDK命令行工具查看
public class App {
public static void main(String[] args) {
for (;;) {}
}
}
1.1、jps
列出当前机器上正在运行的虚拟机进程。
| 常用参数 | 作用 |
|---|---|
| -p | 仅仅显示进程ID |
| -m | 输出虚拟机进程启动时传递给主类main()函数的参数 |
| -l | 输出主类的全名,如果进程执行的是Jar包,输出Jar路径 |
| -v | 输出虚拟机进程启动时JVM参数 |

1.2、jstat
可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,在没有GUI图形界面,只提供了纯文本控制台环境的服务器上。
| 选项 | 作用 |
|---|---|
| -class | 监视类装载、卸载数量、总空间以及类装载所耗费的时间 |
| -gc | 监视Java堆状况,包括Eden区、两个Survivor区、老年代、永久代等容量、 已用空间、GC时间等合计信息 |
| -gccapacity | 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间 |
| -gccause | 监视内容与-gc基本相同,但是会额外输出导致上一次GC产生的原因 |
| -gcutil | 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比 |
| -gcnew | 监视新生代GC状况 |
| -gcnewcapacity | 监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间 |
| -gcold | 监视老年代GC状况 |
| -gcoldcapacity | 监视内容与-gcold基本相同,输出主要关注使用的最大、最小空间 |
| -gcpermcapacity | 输出永久代使用到的最大、最小空间 |
| -compiler | 输出JIT编译器编译过的方法、耗时等信息 |
| -printcompilation | 输出以及被JIT编译的方法 |
-
查看类装载、卸载数量、总空间以及类装载时间情况

-
查看GC情况

选项 作用 S0C Survivor0区容量 S1C Survivor1区容量 S0U Survivor0区已使用容量 S1U Survivor1区已使用容量 EC Eden区容量 EU Eden区已使用容量 OC 老年代的容量 OU 老年代已使用的容量 MC 元空间(MetaSpace)的容量(JDK1.8) MU 元空间(MetaSpace)已使用容量(JDK1.8) CSSC 压缩类的容量 CSSU 压缩类已使用容量 YGC 发生YoungGC的次数 YGCT 发生YoungGC所消耗的时间 FGC 发生FullGC的次数 FGCT 发生FullGC所消耗的时间 GCT 表示垃圾收集消耗的总时间 另外命令后面还可以再加上查询间隔时间及查询次数,如每隔250毫秒查询一次我们运行的App垃圾收集状况,一共查询5次

-
查看上一次GC产生的原因

1.3、jinfo
实时地查看和修改虚拟机各项参数。
比如可以使用 jinfo -flag PrintGC 来实时地查看是否开启了打印GC的日志,如下:

这里默认是关闭的,如果有需要,是可以通过执行 jinfo -flag +PrintGC 开启和 jinfo -flag -PrintGC 关闭的

但是要注意的是,不是所有的参数我们都可以进行修改,由 java -XX:+PrintFlagsFinal –version 查询出来,并且以 {manageable} 的结束的参数才可以进行修改

另外还有一个参数 jinfo -sysprops <pid> 可以打印系统中的参数,其中各项的值就是在代码中 System.getProperties("xx") 获取到的值。
1.4、jmap 和 jhat
用于生成堆转储快照(一般称为 heapdump 或 dump 文件)。

上图中使用了 jmap 生成了一个正在运行程序的 jump 快照文件,这里可以使用 jhat 来分析生成的堆转储快照。

由于默认端口7000被本机系统进程占据了,这里需要使用-port xxxx修改端口,启动完成后就可以在浏览器中进行访问查看

1.5、jstack
用于生成虚拟机当前时刻的线程快照(一般称为 threaddump 或者 javacore 文件)。
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。
这里就来启动下列一段死锁代码,然后用jstack来查看
public class Client {
public static void main(String[] args) {
DeadLock deadLock = new DeadLock();
new Thread(deadLock::ab).start();
new Thread(deadLock::ba).start();
}
}
class DeadLock {
private Object a = new Object(), b = new Object();
public void ab() {
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "拿到了a锁,准备拿b锁...");
try {
Thread.sleep(100); //休眠100毫秒,让ba方法有机会拿到b锁
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "拿到了b锁...");
}
}
}
public void ba() {
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "拿到了b锁,准备拿a锁...");
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "拿到了a锁...");
}
}
}
}



1.6、可视化工具
1.6.1、jconsole
jconsole是一种基于JMX的可视化监视、管理工具。

打开之后,发现会有本地进程和远程进程,如果想要的连接远程进程,则需要在远程应用的启动参数中进行配置,不过因为安全等问题,一般也不会开启远程连接。

然后看到在内存模块中各个区域内的使用情况,其中右侧的执行GC就相当于我们在程序中的System.gc()

1.6.2、visualvm
visualvm相对于jconsole来说,功能要相对强大一些,它主要可以在 https://visualvm.github.io 中安装插件。



但是注意版本问题,不同的JDK所带的 visualvm 是不一样的,下载插件时需要下对应的版本,不过和jconsole一样,一般来说该工具只是用来在本机调试使用。
比如安装的Visual GC这个插件,可以图形化的查看GC发送的次数,消耗的时间,发生GC的原因,内存容量和已使用容量等等的一些信息。

二、Arthas
Arthas 是阿里开源的Java诊断工具,支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,执行Tab键填充功能,官方文档:https://arthas.aliyun.com/doc
2.1、安装启动
下载 arthas-boot.jar ,然后用 java -jar 的方式启动:
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
这里启动了上述介绍的死锁代码,然后进行查看,如下:

基础命令:
| 命令 | 说明 |
|---|---|
| cls | 清空当前屏幕区域 |
| history | 打印历史命令,打印出你在使用arthas过程中输入了哪些命令 |
| help | 查看命令帮助信息 |
2.2、常用命令
2.2.1、dashboard
会展示当前进程的信息,该界面是实时刷新,每5s刷新一次,按 q 或 ctrl+c 可以中断执行

2.2.2、thread
这个命令和 jstack 很相似,但是功能更加强大,主要是查看当前 JVM 的线程堆栈信息,同时可以结合使用 thread –b 来进行死锁的排查死锁。
常用参数解释:
- -b: 查找阻塞当前线程的线程
- -i: 指定 cpu 占比统计的采样间隔,单位为毫秒
- -n: 指定最忙的前 n 个线程并打印堆栈
- -h: 查看 thread 命令帮助信息
查找阻塞当前线程的线程

每隔1000毫秒进行采样,查看最占CPU资源的前3个线程

2.2.3、jad
反编译指定已加载类的源码,可使用 Tab 键进行提示目录,如下:

2.2.4、trace
可以跟踪方法内部调用路径,并输出方法路径上的每个节点上耗时。
trace com.test.ClassA methodName
2.2.5、watch
能方便的观察到指定函数的调用情况,能观察到的范围为:返回值、抛出异常、入参。
watch com.test.ClassA methodName
后面还可以再加上想要观察的参数,默认为:{params, target, returnObj}
三、MAT
基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。
使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。
下载地址:https://www.eclipse.org/mat/downloads.php,把下载好的压缩包解压到本地即可使用。
然后在启动应用程序时,加上JVM的启动参数 -XX:+HeapDumpOnOutOfMemoryError ,这个参数可以让虚拟机在出现内存溢出异常时 dump 出当前内存堆转储快照以便时候进行分析,然后我们在执行上述代码,结果如下:

那么虚拟机在出现内存溢出异常时Dump出当前内存堆转储快照存储在什么地方呢?
它一般在我们项目路径下,和我们的 src 路径同级(另外我们也是可以指定相应的目录的,可使用 -XX:HeapDumpPath=xxx 参数进行设置),这里我们使用刚刚下载的 MAT 工具将其打开


然后MAT就能帮助我们分析刚刚的快照文件,并给出相应的分析结果,我们查看其分析结果


浅堆(Shallow Heap): 是指一个对象所消耗的内存。
深堆 (Retained Heap): 这个对象被GC回收后,可以真实释放的内存大小,也就是只能通过对象被直接或间接访问到的所有对象的集合。通俗地说,就是指仅被对象所持有的对象的集合。深堆是指对象的保留集中所有的对象的浅堆大小之和。
如何理解浅堆和深堆呢?看下图:

对象A引用了对象C和对象D,对象B引用了对象C和对象E。
那么对象A的浅堆大小只是A本身,不含C和D,而A的实际大小为A、C、D三者之和。而A的深堆大小为A与D之和,因为对象C还可以通过对象B访问到,因此不在对象A的深堆范围内。
本文详细介绍了Java虚拟机的监控和故障处理工具,包括JDK自带的命令行工具如jps、jstat、jinfo、jmap、jhat、jstack以及可视化工具jconsole和visualvm。此外,还讲解了阿里开源的Arthas工具,以及内存分析工具MAT的使用方法,帮助开发者定位和解决性能问题。

351

被折叠的 条评论
为什么被折叠?



