Java 常用命令及问题分析工具

目录

前言

当线上出现卡顿以及涉及到 Java 性能分析时,需要使用一些 Java 提供的分析工具进行问题的定位,有一系列强大的命令和工具可以帮助开发人员分析应用程序的性能瓶颈、内存使用情况和线程问题。本文会对一些常用命令和工具做说明和示例。

以下是一些常用的命令和工具汇总:

命令 功能描述
jps 列出当前用户启动的Java进程。
jinfo 查看正在运行的Java程序的JVM参数,并且支持运行时修改个别参数
jmap 生成Java应用程序的堆快照和对象的统计信息,也可以查看运行时内存占用信息
jstat 用于观察Java程序的运行时信息,常用于查看GC相关的堆信息
jstack 查看应用程序的线程栈信息,常用于检测死锁
jconsole Java 自带的监控和管理控制台,它提供了一个图形化界面,允许您监视和管理正在运行的 Java 应用程序的性能和资源使用情况
jvisualvm Java 自带的一款功能强大的多合一故障诊断和性能监控的图形化工具

PS:本文使用JDK1.8

一、jps

jps (JVM Process Status Tool)命令用于列出当前用户正在运行的 Java 进程信息,包括进程 pid 和主类名。这对于迅速了解系统上正在运行的 Java 应用程序很有帮助。

1.1、语法

bash 复制代码
jps [ options ] [ hostid ]

其中,options 是可选的命令行选项,hostid 是可选的 RMI 注册表主机 ID。下面是一些常用的选项:

  • -q:只输出进程ID,不包括类名和 jar 文件名。

  • -m:输出传递给 main 方法的参数。

  • -l:输出主类全名,或者对于jar文件,输出jar文件路径。

  • -v:输出传递给 jar的参数。

1.2、示例

一般jps常用的就两个命令,一个不带options 一个options使用-l,这里假设有一个真正运行的Java程序,主类为MyApp

示例:

  • 1、查看当前用户所有的 Java 进程的进程 ID 和主类名
bash 复制代码
$ jps
27308 Jps
29388 MyApp
  • 2、查看当前用户所有的 Java 进程的进程 ID 和主类全名,或者jar路径
bash 复制代码
$ jps -l
27308 sun.tools.jps.Jps
29388 com.kerwin.jvm.tools.MyApp

二、jinfo

jinfo 用于查看和修改正在运行的 Java 进程的 Java 虚拟机(JVM)参数和系统属性。通过使用 jinfo可以动态地检查和更改 Java 应用程序的配置信息,而无需停止应用程序,常用于查看 JVM 参数的当前值。

2.1、语法

bash 复制代码
jinfo [options] pid

options 是可选的命令行选项,pid 是正在运行的Java进程的进程ID,下面是一些常用的选项:

  • -flags:打印指定Java进程的 JVM 参数值。
  • -sysprops:打印Java虚拟机的系统属性。
  • -flag name:打印指定名称的标志参数的值。
  • -flag [+|-]name:打印或设置指定名称的布尔标志参数的值。

2.2、示例

bash 复制代码
jinfo [options] pid
  • 1、jinfo -flags pid 查看标志参数
bash 复制代码
$ jinfo -flags 29388
Attaching to process ID 29388, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.281-b09
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=536870912 -XX:MaxHeapSize=8573157376 -XX:MaxNewSize=2857369600 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=178782208 -XX:OldSize=358088704 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:
  • 2、jinfo -sysprops pid 查看系统属性
bash 复制代码
$ jinfo -sysprops 29388
Attaching to process ID 29388, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.281-b09
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.281-b09
sun.boot.library.path = C:\Program Files\Java\jdk1.8.0_281\jre\bin
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = ;
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
...
  • 3、jinfo -flag PrintGC pid 查看特定标志参数的值
bash 复制代码
$ jinfo -flag PrintGC 29388
-XX:-PrintGC
  • 4、jinfo -flag +PrintGC pid 修改特定标志参数的值(不是所有参数都支持动态修改)
bash 复制代码
$ jinfo -flag +PrintGC 29388

$ jinfo -flag PrintGC 29388
-XX:+PrintGC

三、jmap

jmap(Java Memory Map)命令用于生成 Java 进程的内存映射信息。它提供了堆的详细信息,包括 Java 堆内存、对象统计和内存使用情况的详细信息,可以帮助开发人员分析内存泄漏、内存使用情况等问题。

3.1、语法

bash 复制代码
jmap [options] pid

options 是一些可选的命令选项,pid 是 Java 程序的进程 ID,下面是一些常用的选项:

  • -heap: 显示Java堆内存使用情况。

  • -histo: 显示Java堆内存中的对象统计信息。

  • -dump:<format>=<file>: 将堆内存转储到文件,其中为转储格式(如b, c, hprof),为目标文件名。

  • -finalizerinfo: 显示等待终结者队列中的对象。

  • -F: 在无法连接到进程时,强制执行转储操作。

3.2、示例

  • 1、jmap -heap pid查看 Java 堆内存信息和使用信息
bash 复制代码
$ jmap -heap 29388
...
Parallel GC with 6 thread(s)
Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 8573157376 (8176.0MB)
   NewSize                  = 178782208 (170.5MB)
   MaxNewSize               = 2857369600 (2725.0MB)
   OldSize                  = 358088704 (341.5MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
   ...
From Space:
   ...
To Space:
   ...
PS Old Generation
   ...
  • 2、使用jmap命令生成堆内存转储文件
bash 复制代码
jmap -dump:format=b,file=heapdump.hprof 29388

通过这个命令会生成一个heapdump.hprof转储文件到当前目录,可以使用jvisualvm或者IDEA直接打开,个人推荐使用IDEA直接打开,将文件拖拽到IDEA即可。

注意事项:

  • 使用jmap命令时,建议在测试或开发环境中进行,避免在生产环境中使用,因为生成堆内存转储文件可能会影响应用程序的性能。
  • jmap命令可能需要JVM的调试权限,因此确保您有足够的权限来运行该命令。
  • 转储文件可能会相当大,特别是在内存使用量较大的情况下。确保您有足够的磁盘空间来存储转储文件。

四、jstat

jstat命令监视 Java 虚拟机(JVM)的各种统计信息

4.1、语法

bash 复制代码
# jstat <-命令选项> [-t] [-h<lines>] <pid> [<间隔时间/毫秒> [查询次数]]
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
  • -option: 参数选项。
  • -t: 可以在打印的列加上 Timestamp 列,用于显示系统运行的时间。
  • -h: 可以在周期性数据输出的时候,指定输出多少行以后输出一次表头。
  • vmid: Virtual Machine ID(进程的 pid)。
  • interval: 执行每次的间隔时间,单位为毫秒。
  • count: 用于指定输出多少次记录,缺省则会一直打印。

4.2、常用命令

4.2.1、-class:显示加载 class 数量及所占空间
bash 复制代码
$ jstat -class 29388
Loaded  Bytes  Unloaded  Bytes     Time
   481   985.9        0     0.0       0.08
  • Loaded:加载类的数量
  • Bytes:加载类的size,单位为Byte
  • Unloaded:卸载类的数目
  • Bytes:卸载类的size,单位为Byte
  • Time:加载与卸载类花费的时间
4.2.2、-compiler:显示VM实时编译的数量
bash 复制代码
$ jstat -compiler 29388
Compiled Failed Invalid   Time   FailedType FailedMethod
     126      0       0     0.15          0
  • Compiled:编译任务执行数量
  • Failed:编译任务执行失败数量
  • Invalid:编译任务执行失效数量
  • Time:编译任务消耗时间
  • FailedType:最后一个编译失败任务的类型
  • FailedMethod:最后一个编译失败任务所在的类及方法
4.2.3、-gc:显示gc的次数及时间
bash 复制代码
$ jstat -gc 29388 
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
21504.0 21504.0  0.0    0.0   131584.0 10526.8   349696.0    0.0     4480.0 788.1  384.0   76.6   0      0.000    0     0.000   0.000
  • S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
  • S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
  • S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
  • S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
  • EC:年轻代中Eden(伊甸园)的容量 (字节)
  • EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
  • OC:老年代的容量 (字节)
  • OU:老年代目前已使用空间 (字节)
  • MC:metaspace(元空间)的容量 (字节)
  • MU:metaspace(元空间)目前已使用空间 (字节)
  • CCSC:当前压缩类空间的容量 (字节)
  • CCSU:当前压缩类空间目前已使用空间 (字节)
  • YGC:从应用程序启动到采样时年轻代中gc次数
  • YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
  • FGC:从应用程序启动到采样时老年代(全gc)gc次数
  • FGCT:从应用程序启动到采样时老年代(全gc)gc所用时间(s)
  • GCT:从应用程序启动到采样时gc用的总时间(s)
4.2.4、-gccapacity:显示VM内存中三代(young/old/perm)对象的使用和占用大小
bash 复制代码
$ jstat -gccapacity 29388
 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC
174592.0 2790400.0 174592.0 21504.0 21504.0 131584.0 349696.0  5581824.0   349696.0   349696.0  0.0    1056768.0   4480.0   0.0 1048576.0    384.0      0     0
  • NGCMN:年轻代(young)中初始化(最小)的大小(字节)
  • NGCMX:年轻代(young)的最大容量 (字节)
  • NGC:年轻代(young)中当前的容量 (字节)
  • S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
  • S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
  • EC:年轻代中Eden(伊甸园)的容量 (字节)
  • OGCMN:老年代中初始化(最小)的容量大小 (字节)
  • OGCMX:老年代的最大容量(字节)
  • OGC:老年代当前新生成的容量 (字节)
  • OC:老年代的容量 (字节)
  • MCMN:metaspace(元空间)中初始化(最小)的大小 (字节)
  • MCMX:metaspace(元空间)的最大容量 (字节)
  • MC:metaspace(元空间)当前新生成的容量 (字节)
  • CCSMN:最小压缩类空间大小
  • CCSMX:最大压缩类空间大小
  • CCSC:当前压缩类空间大小
  • YGC:从应用程序启动到采样时年轻代中gc次数
  • FGC:从应用程序启动到采样时老年代(全gc)gc次数
4.2.5、-gcutil:统计gc信息百分比
bash 复制代码
$ jstat -gcutil 29388
jstat -gcutil 29388
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00   8.00   0.00  17.59  19.94   0      0.000    0    0.000    0.000
  • S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
  • S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
  • E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
  • O:old代已使用的占当前容量百分比
  • M:元数据区已使用的占当前容量百分比
  • CCS:压缩类空间已使用的占当前容量百分比
  • YGC :从应用程序启动到采样时年轻代中gc次数
  • YGCT :从应用程序启动到采样时年轻代中gc所用时间(s)
  • FGC :从应用程序启动到采样时old代(全gc)gc次数
  • FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
  • GCT:从应用程序启动到采样时gc用的总时间(s)
4.2.6、-gccause:显示最近一次GC统计和原因
bash 复制代码
$ jstat -gccause 29388
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC
  0.00   0.00   8.00   0.00  17.59  19.94   0     0.000     0    0.000    0.000 No GC                No GC
  • LGCC:最后一次GC原因
  • GCC:当前GC原因(No GC 为当前没有执行GC)

五、jstack

jstack是用于输出Java应用程序的线程栈信息,常用来查看线程是否有死锁,以及CPU飙高问题定位。

5.1、语法

bash 复制代码
$ jstack [ options ] pid

options 是命令选项,pid 是目标 Java 进程的进程 ID。以下是一些常用的命令选项:

  • -F:强制生成线程堆栈,即使Java进程没有响应。

  • -m:除了线程堆栈,还包括每个线程的本地(本地方法)信息。

  • -l:除了线程堆栈,还包括锁信息。

  • -h:显示帮助信息。

5.2、示例

这里模拟一个死锁例子

java 复制代码
public class DeadLockMain {
    private static Object A = new Object();
    private static Object B = new Object();

    public void deadLock() {

        Thread t1 = new Thread(() -> {
            synchronized (A) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                    System.out.println("thread1");
                }
            }
        });
        Thread t2 = new Thread(() -> {
            synchronized (B) {
                synchronized (A) {
                    System.out.println("thead2");
                }
            }
        });
        t1.start();
        t2.start();
    }

    public static void main(String[] args) {
        new DeadLockMain().deadLock();
    }
}

上述代码是一个简单的会发生死锁的例子,两个线程分别持有A和B,并分别请求B和A,导致死锁产生。使用jstack打印上述进程的线程栈信息,如果出现死锁信息会在最下面输出一个Found one Java-level deadlock信息,部分输出如下:

java 复制代码
...
$ jstack 14280
2024-02-20 17:28:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.281-b09 mixed mode):

"DestroyJavaVM" #15 prio=5 os_prio=0 tid=0x0000012b0878d800 nid=0x445c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" #14 prio=5 os_prio=0 tid=0x0000012b2e3ec800 nid=0x274c waiting for monitor entry [0x00000015e25ff000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$1(DeadLockMain.java:25)
        - waiting to lock <0x0000000715ce6d70> (a java.lang.Object)
        - locked <0x0000000715ce6d80> (a java.lang.Object)
        at com.kerwin.jvm.tools.DeadLockMain$$Lambda$2/1711574013.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

"Thread-0" #13 prio=5 os_prio=0 tid=0x0000012b2e3ec000 nid=0x405c waiting for monitor entry [0x00000015e24ff000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$0(DeadLockMain.java:18)
        - waiting to lock <0x0000000715ce6d80> (a java.lang.Object)
        - locked <0x0000000715ce6d70> (a java.lang.Object)
        at com.kerwin.jvm.tools.DeadLockMain$$Lambda$1/754666084.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x0000012b2d19c3a8 (object 0x0000000715ce6d70, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x0000012b2d1a0448 (object 0x0000000715ce6d80, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$1(DeadLockMain.java:25)
        - waiting to lock <0x0000000715ce6d70> (a java.lang.Object)
        - locked <0x0000000715ce6d80> (a java.lang.Object)
        at com.kerwin.jvm.tools.DeadLockMain$$Lambda$2/1711574013.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
"Thread-0":
        at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$0(DeadLockMain.java:18)
        - waiting to lock <0x0000000715ce6d80> (a java.lang.Object)
        - locked <0x0000000715ce6d70> (a java.lang.Object)
        at com.kerwin.jvm.tools.DeadLockMain$$Lambda$1/754666084.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.
相关推荐
小林想被监督学习18 分钟前
Java后端如何进行文件上传和下载 —— 本地版
java·开发语言
Erosion202027 分钟前
SPI机制
java·java sec
猪猪虾的业余生活29 分钟前
matlab实现,数据曲线毛刺光滑
开发语言·matlab
HABuo1 小时前
【数据结构与算法】合并链表、链表分割、链表回文结构
c语言·开发语言·数据结构·c++·学习·算法·链表
逸风尊者1 小时前
开发也能看懂的大模型:RNN
java·后端·算法
望获linux1 小时前
在 ARM 平台上如何实现Linux系统的1秒启动
linux·服务器·开发语言·数据库·操作系统·嵌入式操作系统·arm平台
带多刺的玫瑰1 小时前
Leecode刷题C语言之网络延迟时间
c语言·开发语言·算法
尘浮生1 小时前
Java项目实战II基于Java+Spring Boot+MySQL的智能停车计费系统(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·mysql·微信小程序·maven
先天打工圣体的男人1 小时前
Linux中安装InfluxDB
linux·运维·服务器
frost-cold1 小时前
【JavaEE】Servlet:表白墙
java·servlet·java-ee