一、基本情况

jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。常用于检测垃圾回收问题以及内存泄漏问题。

官方文档:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

二、基本语法

它的基本使用语法为:
jstat -

2.1、option参数

选项option可以由以下值构成。

  • 类装载相关的:
    • -class: 显示ClassLoader的相关信息:类的装载、卸载数量、总空间、类装载所消耗的时间等
  • 垃圾回收相关的:
    • -gc: 显示与GC相关的堆信息。包括Eden区、两个Survivor区、老年代、永久代等的容量、己用空间、GC时间合计等信息。
      • image.png
      • S0C:新生者0区容量,S1C:新生者1区容量,S0U:新生者0区已使用的容量,S1U:新生者1区已使用的容量
      • EC:伊甸园区总容量,EU:伊甸园已使用的容量
      • OC:老年代总容量,OU:老年代已使用的容量
      • MC:方法区总容量,MU:方法区已使用的容量
      • CCSC:压缩类的总容量,CCSU:压缩类已使用的容量
      • YGC:发生young GC的次数,YGCT:young GC消耗的时间
      • FGC:Full GC次数,FGCT:Full GC消耗的时间,GCT:总GC时间
    • -gccapacity: 显示内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间。
    • -gcutil: 显示内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比。
      • image.png
    • -gccause: 与 -gcutil 功能一样,但是会额外输出导致最后一次或当前正在发生的GC产生的原因。
    • -gcnew: 显示新生代GC状况
    • -gcnewcapacity: 显示内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
    • -geold: 显示老年代GC状况
    • -gcoldcapacity: 显示内容与-gcold基本相同,输出主要关注使用到的最大、最小空间
    • -gcpermcapacity: 显示永久代使用到的最大、最小空间。
  • JIT相关的:
    • -compiler: 显示JIT编译器编译过的方法、耗时等信息
    • -printcompilation: 输出已经被JIT编译的方法

      举例:

      1. public class ScannerTest {
      2. public static void main(String[] args) {
      3. System.out.println(args.length);
      4. System.out.println(args[0]);
      5. Scanner scanner = new Scanner(System.in);
      6. String info = scanner.next();
      7. }
      8. }
      image.png
loaded Bytes Unloaded Bytes Time
加载类的个数 加载当前类的所占用的字节数 卸载类的个数 卸载类所占用的字节数 总耗时

-compiler: 显示JIT编译器编译过的方法、耗时等信息
image.png
-printcompilation: 输出已经被JIT编译的方法
image.png
-gc: 显示与GC相关的堆信息。包括Eden区、两个Survivor区、老年代、永久代等的容量、己用空间、GC时间合计等信息。

  1. package studies.jvm.jps;
  2. import java.util.ArrayList;
  3. /**
  4. * @Date: 2021/5/10
  5. * @Time: 19:49
  6. * @BelongsProject base
  7. * @BelongsPackage studies.jvm.jps
  8. * @Description: -Xms60m -Xmx60m -XX:SurvivorRatio=8
  9. */
  10. public class GCTest {
  11. public static void main(String[] args) {
  12. ArrayList<byte[]> list = new ArrayList<>();
  13. for (int i = 0; i < 1000; i++){
  14. byte[] arr = new byte[1024 * 100];//100kb
  15. list.add(arr);
  16. try {
  17. Thread.sleep(120);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }
  23. }

image.png
image.png
内存设置的大小为60M,新生代默认比例为2(newRatio=2),新生代20M,老年代40M。因为设置了SurvivorRatio=8,那新生代中S0C为2M,S1C为2M,伊甸园区占16M

2.2、interval参数

用于指定输出统计数据的周期,单位为毫秒。即:查询间隔
每隔一秒打印一次
image.png

2.3、count参数

用于指定查询的总次数
不加interval和count默认只查一次
image.png

2.4、-t参数

可以在输出信息前加上一个Timestamp列,显示程序的运行时间。单位:秒
image.png
显示程序运行的总时间

经验:
我们可以比较Java进程的启动时间以及总 GC 时间(GCT 列),或者两次测量的间隔时间以及总GC时间的增量,来得出GC时间占运行时间的比例。
如果该比例超过20%,则说明目前堆的压力较大;如果该比例超过90%,则说明堆里几乎没有可用空间,随时都可能抛出OOM异常。
image.png

2.5、-h参数

可以在周期性数据输出时,输出多少行数据后输出一个表头信息
image.png
-h2是每两条数据都打印一次表头

**

三、补充

jstat还可以用来判断是否出现内存泄漏。

第1步:
在长时间运行的Java程序中,我们可以运行jstat命令连续获取多行性能数据,并取这几行数据中 OU列(即已占用的老年代内存)的最小值。

第2步:
然后,我们每隔一段较长的时间重复一次上述操作,来获得多组OU最小值。如果这些值呈上涨趋势,则说明该Java程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏。