⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 江南一点雨 「江南一点雨」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

虽然阿里巴巴的 Arthas 这个工具很强大,不过如果你能够熟练使用 JDK 提供的工具,那么在不借助任何外力的情况下,就可以非常轻松的进行应用的性能监控和故障处理。

JDK 提供的工具,大家最熟悉的估计就是 java 和 javac 这两个了,然而 JDK 实际上提供了非常强大的性能监控和调试工具,今天松哥就来和大家一起捋一捋这些工具。

一 jps

这个应该是大家最为熟悉的工具了,使用这个命令可以快速列出来系统上正在运行的 Java 进程。

这个命令在执行的时候一般有四个参数:

  • -q 表示只输出进程 ID,不输出主类名称,准确来说,这里输出的叫做本地虚拟机进程 ID(LVMID),不过对于本地虚拟机进程来说,LVMID 和操作系统的进程 ID 是一致的。
  • -l 表示输出主类的全名,如果进程执行的是 jar 包,那么就输出 jar 包的完整路径。
  • -m 表示输出进程启动时传递给 main() 函数的参数。
  • -v 表示输出进程启动时的 JVM 参数。

二 jstat

jstat 是用来监控虚拟机各种运行状态信息的命令行工具,这个工具可以用来查看本地或者远程虚拟机内存、垃圾收集、即时编译等等信息。

一般来说,这些数据我们可以借助可视化工具来查看,例如 JMC 或者 VisualVM 等等,但是有时候在服务器环境下,在命令行环境下没法运行 GUI 图形界面,那么此时 jstat 是一个不错的选择。

jstat 运行参数比较多,松哥这里列举几个比较常见的参数:

  • -class 这个表示监视类加载、卸载数量、总空间以及类装载所耗费的时间。

  • -gc 这个表示监视 Java 堆状况,包括 Eden 区,两个 Survivor 区、老年代以及永久带的容量,已使用的空间以及垃圾收集时间合计等等信息。

命令中的 1s 8 表示每秒打印一次,一共打印 8 次,如果不设置,则打印一次。

这里输出的各参数含义如下:

❝

S0C:Survivor0 的容量。S1C:Survivor1 的容量。S0U:Survivor0 已使用大小。S1U:Survivor1 已使用大小。EC:Eden 区容量。EU:Eden 区已使用大小。OC:老年代容量。OU:老年代已使用大小。MC:元数据区容量。MU:元数据区已使用大小。CCSC:压缩类空间容量。CCSU:压缩类空间已使用大小。YGC:年轻代垃圾回收次数。YGCT:年轻代垃圾回收总耗时。FGC:FullGC 次数。FGCT:FullGC 总耗时。CGC:GC STW 的次数。CGCT:GC STW 的时间。GCT:总 GC 时间。

基本上我们想知道的关于 JVM 运行内存状态的信息,这里都有了。

  • -gccapacity 这个监控内容与 -gc 类似,不过输出内容主要关注 Java 堆各个区域使用到的最大最小空间。

这里涉及到的参数我也和大家稍微解释下:

❝

NGCMN:新生代最小容量。NGCMX:新生代最大容量。NGC:新生代当前容量。OGCMN:老年代最小容量。OGCMX:老年代最大容量。OGC:老年代当前容量。MCMN:元空间最小容量。MCMX:元空间最大容量。CCSMN:压缩类空间最小容量。CCSMX:压缩类空间最大容量。CCSC:压缩类空间当前容量。

补充输出内容和前面一致的我就不重复解释了。

  • -gcutil 这个和 -gc 类似,不过输出的内容主要关注已使用的空间占总空间的比例。

❝

S0:Survivor0 区使用比例。S1:Survivor1 区使用比例。E:Eden 区使用比例。O:老年代使用比例。M:元空间使用比例。CCS:压缩类空间使用比例。

这块能加的参数实际上非常多,对于我们来说比较常用的主要就是上面这几个命令。

如果小伙伴们想要查看完整指令,可以参考官方文档:https://docs.oracle.com/en/java/javase/11/tools/jstat.html

三 jinfo

jinfo 命令可以实时查看和修改 JVM 各项参数。

能修改这就很牛了。

平时我们启动一个 Java 项目,一旦启动之后,如果想要知道项目启动时的各项 JVM 参数,那么就只能去查文档了。但是如果你能够熟练使用 jinfo,那么这个事情就容易很多了。

直接 jinfo pid 就会展示出来所有的 JVM 参数。

如果只想查看某一个 JVM 参数,那么可以使用如下命令:

jinfo -flag CICompilerCount 28893

也可以在不重启 JVM 参数的情况下,动态修改 JVM 参数。

例如松哥这里的案例,原本是没有开启 PrintClassHistogram 的,我现在动态开启:

PrintClassHistogram 前面没有符号,表示查看当前状态;PrintClassHistogram 前面有个 + 表示开启;PrintClassHistogram 前面有个 - 表示关闭。

这种方式是修改 value 为 boolean 的 JVM 参数,如果是 key-value 格式的 JVM 参数,那么可以按照下面这种方式修改:

当然这个修改并非所有的 JVM 参数都能改,至于哪些 JVM 参数能改,我们可以执行 java -XX:+PrintFlagsInitial 命令,找到标记为 manageable 的参数,这些参数是可以动态修改的。

另外我们在代码中通过 System.getProperties() 获取到的属性,也可以通过指令打印出来:

jinfo -sysprops 57002

四 jmap

jmap 命令一般可以用来生成 heapdump。

这个命令在新版本 JDK 中运行的时候,前面要加上 jhsdb。

从这里我们可以解读出哪些信息呢?

  • 可以看到最大可分配的 Heap 大小(MaxHeapSize)
  • 可以看到 JVM 启动时分配的新生代内存(NewSize)
  • 可以看到可分配的最大新生代内存(MaxNewSize)
  • 可以看到 JVM 启动时分配的老年代大小(OldSize)
  • 可以看到老年代和新生代的内存比例(NewRatio),上面截图中表示 老/新=2,即老年代占 2/3,新生代占 1/3。
  • 可以看到新生代中 Eden 区和一个 Survivor 区的比例(SurvivoRatio)
  • 可以看到初始的 Metaspace 大小(MetaspaceSize)
  • 可以看到最大的 Metaspace 大小(MaxMetaspaceSize)
  • 可以看到在 G1 收集器下,每个 Region 的大小(G1HeapRegionSize)

下面的这些就好理解了,分别是不同区域的 regions 数量、总空间、使用空间以及空闲空间。

也可以利用 jmap 查看 Heap 中对象的统计信息,比如对象的数量、占用内存的大小以及类的完整路径。

jmap -histo:live pid

加上 :live 表示查看活着的对象信息。

也可以查看 Heap 中元空间的类加载信息 jmap -clstats 28893。

这里可以看到有哪些类加载器,分别加载了哪些类。

当然,最重要的功能是生成 dump 文件了:

这里几个参数说明一下:

  • live 表示只转存堆中活动对象,如果没有制定,则存所有对象。
  • format=b 表示以 hprof 二进制格式转存。
  • file=xxx 表示生成的文件名。

生成的文件,可以使用 idea 打开查看。

❝

小技巧:获取 heapdump 还有哪些方式?

  1. 使用 kill -3 吓一吓 JVM,就能拿到堆转储快照。
  2. -XX:HeapDumpOnOutOfMemoryError 参数可以让虚拟机在内存溢出时自动生成堆转储快照。

五 jhat

这个工具目前已经废弃了。

松哥这里就简单说下这个工具的作用以及替代品。

前面 jmap 会生成 heapdump 文件,这是一个二进制文件,那么我们通过什么工具去分析这个文件呢?比如可以使用 Eclipse 的 MAT,当然现在 IDEA 也可以直接打开这个文件分析,这块成熟的工具还是非常多的。

那么 jhat 其实也是一个这样的工具,jhat 内置了一个微型的 Web 服务器,让开发者可以在浏览器中查看相关数据。但是因为 jhat 功能比较简陋,所以目前已经废弃了。

六 jstack

jstack 可以查看 JVM 当前时刻的线程快照。

如果某个线程执行比较耗时,或者发生死锁,发生死循环等,那么就可以通过这个指令来查看各个线程的调用堆栈,检查到底发生了什么问题。

-l 表示出了堆栈之外,也把锁的相关信息显示出来。

不过这个命令松哥并不常用。因为 Thread 中有一个 getAllStackTraces 方法,我们通过 jstack 命令获取到的信息基本上通过这个方法都能获取到,所以可以自己结合这个方法写监控页面查看相关信息。

文章目录
  1. 1. 一 jps
  2. 2. 二 jstat
  3. 3. 三 jinfo
  4. 4. 四 jmap
  5. 5. 五 jhat
  6. 6. 六 jstack