文章来源:https://mp.weixin.qq.com/s/9yuoft2qabcITVIAyY3ZTw

作者:武培轩

这篇文章主要来介绍下 JDK 内置的命令,话不多说,让我们开始吧!

Javap

使用 javap 可以查看 Java 字节码反编译的源文件,javap 的命令格式如下:

Java不可变对象(Java不可不知的)(1)

下面来演示下用 javap -c 对代码进行反编译,首先写个 HelloWorld 类,如下:

Java不可变对象(Java不可不知的)(2)

接着使用 javap -c HelloWorld.class 就可以反编译得到如下结果:

Java不可变对象(Java不可不知的)(3)

jps

jps 是用来查询当前所有进程 pid 的,命令的用法如下图所示:

Java不可变对象(Java不可不知的)(4)

执行 jps 可以获取本机 Java 程序的 pid,运行结果如下:

Java不可变对象(Java不可不知的)(5)

使用 jps -mlvV 可以获取到这个进程的 pid、jar 包的名字以及 JVM 参数等。

Java不可变对象(Java不可不知的)(6)

jstat

jstat 主要用于监控 JVM,主要是 GC 信息,在性能优化的时候经常用到,命令内容如下所示:

Java不可变对象(Java不可不知的)(7)

比如,上面我们通过 jps 查到的进程号 8825,我们使用 jstat -gc 8825 来查看该进程的 GC 信息:

Java不可变对象(Java不可不知的)(8)

其中 S0C 表示当前 Survivor0 的容量,S1C 表示当前 Survivor1 的容量,S0U 表示当前 Survivor0 的利用率,S1U 表示当前 Survivor1 的利用率,EC 表示 Eden 的容量,EU 表示 Eden 的利用率,OC 表示老年代的容量,OU 表示老年代的利用率,MC 表示 Metaspace 的容量,MU 表示 Metaspace 的利用率,CCSC 表示类指针压缩空间容量,CCSU 表示使用的类指针压缩空间,YGC 表示新生代 GC 的次数,YGCT表示新生代 GC 的时间,FGC 表示 Full Gc 的次数,FGCT 表示 Full GC 的时间,GCT表示 GC 总时间。

每个对象都有一个指向它自身类的指针,_klass: 指向类的 4 字节指针,64 位平台上 _klass: 指向类的 8 字节的指针,为了节约这些空间,引入了类指针压缩空间。

jcmd

jcmd 可以查看 JVM 信息,常用的命令内容如下:

Java不可变对象(Java不可不知的)(9)

先使用 jcmd 8825 help 来查看都支持什么命令:

Java不可变对象(Java不可不知的)(10)

下面我就选一个参数给大家举个例子,比如打印堆的信息,使用 jcmd 8825 GC.heap_dump 命令:

Java不可变对象(Java不可不知的)(11)

可以看出可以获取新生代、老年代、元空间、Eden、From Survivor 以及 To Survivor 的大小和占比。

jmap

jmap 打印出 Java 进程内存中 Object 的情况,或者将 JVM 中的堆以二进制输出成文本,命令内容如下:

Java不可变对象(Java不可不知的)(12)

使用 jmap -heap 8825 查看当前堆的使用信息:

Java不可变对象(Java不可不知的)(13)

首先会打印堆的一些相关配置,比如最大新生代、元空间的大小等;下面为堆的使用情况,包括新生代的 Eden 区、S0 区、S1 区以及老年代。

jmap 还可以将堆的信息以文件的形式保存下来,相当于文件快照,执行 jmap -dump:live,format=b,file=heap.bin 8825 命令:

Java不可变对象(Java不可不知的)(14)

这个 heap.bin 可以使用 jhat 命令打开,是以 html 的形式展示的。

jhat

jhat 分析 Java 堆的命令,可以将堆中对象以 html 的形式显示出来,支持对象查询语言 OQL,命令内容如下:

Java不可变对象(Java不可不知的)(15)

现在执行 jhat -port 9999 heap.bin 来将刚刚保存的 heap.bin 以 html 展示出来:

Java不可变对象(Java不可不知的)(16)

执行完毕后,打开 http://localhost:9999/ 就可以看到类的实例的堆占用情况,它是按照包名来分组的:

Java不可变对象(Java不可不知的)(17)

网页的底部还有许多 Query 方式:

Java不可变对象(Java不可不知的)(18)

下面以 OQL 为例,打开后是一个类似 SQL 查询的窗口,比如输入 select s from java.lang.String s where s.value.length >= 100 就可以查询字符串长度大于 100 的实例:

Java不可变对象(Java不可不知的)(19)

jstack

jstack 是堆栈跟踪工具,主要用于打印给定进程 pid 的堆栈信息,一般在发生死锁或者 CPU 100% 的时候排查问题使用,可以去查询当前运行的线程以及线程的堆栈信息是什么情况,命令内容如下:

Java不可变对象(Java不可不知的)(20)

下面执行 jstack -F 8825 > jstack.log 命令,将线程的信息保存下来:

Java不可变对象(Java不可不知的)(21)

因为内容比较多,截取了部分内容,可以看出会打印出线程的信息、状态以及堆栈,也会打印出 GC Task 的线程信息(ParallelGC 属于并行收集器,默认为 2 个线程),从中可以分析出每个线程都在做什么,如果服务器 CPU 占用高,可以看有多少个线程处于 RUNNABLE 状态,一般是由于处于 RUNNABLE 状态的线程过多,导致 CPU 过高;如果很多线程处于 TIMED_WAITING 状态,理论上 CPU 占用不会很高。

总结

本文主要对 JDK 常用的内置命令 javap、jps、jstat、jcmd、jmap、jhat、jstack 进行了简单讲解,大家可以自己在本机进行实践。

了解这些命令后会在死锁、CPU 占用过高问题的排查、程序性能调优上会有很大的帮助,以后还会介绍 JDK 自带的图形化工具以及 CPU 占用过高的排查实例。

对了,在这里说一下,我目前是在职Java开发,如果你现在正在学习Java,了解Java,渴望成为一名合格的Java开发工程师,在入门学习Java的过程当中缺乏基础入门的视频教程,可以关注并私信我:01。获取。我这里有最新的Java基础全套视频教程。

,