性能监控工具

性能监控工具

java进程JPS

jps(JVM Process Status Tool)是 JDK 自带的轻量级命令行工具,默认存放在 $JAVA_HOME/bin 目录下,只有安装 JDK 才会有,单纯的 JRE 环境没有这个命令。它的核心作用是快速列出当前系统中运行的 Java 进程(本质是 JVM 实例),相比 Linux 的 ps -ef | grep java,jps 无需过滤、输出更简洁,且能直接关联 Java 进程的核心信息(如主类、JVM 参数)。

参数说明

-q:只输出进程 ID

-m:输出传入 main 方法的参数

-l:输出完全的包名,应用主类名,jar的完全路径名

-v:输出jvm参数

启动 tomcat

从这个输出中可以看到,当前系统中共存两个Java 应用程序,其中第一个输出Jps就是jps命令本身,这更加证明此命令的本质也是一个Java程序。此外,jps还提供了一系列参数来控制它的输出内容。

参数-q可以指定jps只输出进程ID,而不输出类的短名称:

参数-m可以用于输出传递给Java进程(主函数)的参数:

参数-l可以用于输出主函数的完整路径:

-v表示传递给jvm的参数

jstat查看虚拟机运行时信息

Jstat是JDK自带的一个轻量级工具。全称 Java Virtual Machine statistics monitoring tool,它位于java的bin目录下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控。

option: 参数选项

-t: 可以在打印的列加上Timestamp列,用于显示系统运行的时间

-h: 可以在周期性数据数据的时候,可以在指定输出多少行以后输出一次表头

vmid: Virtual Machine ID (进程的 pid)

interval: 执行每次的间隔时间,单位为毫秒

count: 用于指定输出多少次记录,缺省则会一直打印

选项option可以由以下值构成

-class:显示ClassLoad的相关信息;

-compiler:显示JIT编译的相关信息;

-gc:显示和gc相关的堆信息;

-gccapacity:显示各个代的容量以及使用情况;

-gcmetacapacity:显示metaspace的大小

-gcnew:显示新生代信息;

-gcnewcapacity:显示新生代大小和使用情况;

-gcold:显示老年代和永久代的信息;

-gcoldcapacity:显示老年代的大小;

-gcutil:显示垃圾收集信息;

-gccause:显示垃圾回收的相关信息(通-gcutil),同时显示最后一次或当前正在发生的垃圾回收的诱因;

-printcompilation:输出JIT编译的方法信息;

-class

如下示例输出Java进程38604的ClassLoader相关信息。每秒钟统计一次信息,一共输出两次:

Loaded : 已经装载的类的数量

Bytes : 装载类所占用的字节数

Unloaded:已经卸载类的数量

Bytes:卸载类的字节数

Time:装载和卸载类所花费的时间

-gc

S0C:年轻代中第一个survivor(幸存区)的容量 (字节)

S1C:年轻代中第二个survivor(幸存区)的容量 (字节)

S0U :年轻代中第一个survivor(幸存区)目前已使用空间 (字节)

S1U :年轻代中第二个survivor(幸存区)目前已使用空间 (字节)

EC :年轻代中Eden(伊甸园)的容量 (字节)

EU :年轻代中Eden(伊甸园)目前已使用空间 (字节)

OC :Old代的容量 (字节)

OU :Old代目前已使用空间 (字节)

MC:metaspace(元空间)的容量 (字节)

MU:metaspace(元空间)目前已使用空间 (字节)

YGC :从应用程序启动到采样时年轻代中gc次数

YGCT :从应用程序启动到采样时年轻代中gc所用时间(s)

FGC :从应用程序启动到采样时old代(全gc)gc次数

FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

-gccapacity

可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小

NGCMN :年轻代(young)中初始化的大小 (字节)

NGCMX :年轻代(young)的最大容量 (字节)

NGC :年轻代(young)中当前的容量 (字节)

S0C :年轻代中第一个survivor(幸存区)的容量 (字节)

S1C : 年轻代中第二个survivor(幸存区)的容量 (字节)

EC :年轻代中Eden(伊甸园)的容量 (字节)

OGCMN :old代中初始化(最小)的大小 (字节)

OGCMX :old代的最大容量 (字节)

OGC:old代当前新生成的容量 (字节)

OC :Old代的容量 (字节)

MCMN:metaspace(元空间)中初始化(最小)的大小 (字节)

MCMX :metaspace(元空间)的最大容量 (字节)

MC :metaspace(元空间)当前新生成的容量 (字节)

CCSMN:最小压缩类空间大小

CCSMX:最大压缩类空间大小

CCSC:当前压缩类空间大小

YGC :从应用程序启动到采样时年轻代中gc次数

FGC:从应用程序启动到采样时old代(全gc)gc次数

-gcmetacapacity

metaspace 中对象的信息及其占用量

MCMN:最小元数据容量

MCMX:最大元数据容量

MC:当前元数据空间大小

CCSMN:最小压缩类空间大小

CCSMX:最大压缩类空间大小

CCSC:当前压缩类空间大小

YGC :从应用程序启动到采样时年轻代中gc次数

FGC :从应用程序启动到采样时old代(全gc)gc次数

FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

-gcnew

年轻代对象的信息

S0C :年轻代中第一个survivor(幸存区)的容量 (字节)

S1C :年轻代中第二个survivor(幸存区)的容量 (字节)

S0U :年轻代中第一个survivor(幸存区)目前已使用空间 (字节)

S1U :年轻代中第二个survivor(幸存区)目前已使用空间 (字节)

TT:持有次数限制

MTT:最大持有次数限制

DSS:期望的幸存区大小

EC:年轻代中Eden(伊甸园)的容量 (字节)

EU :年轻代中Eden(伊甸园)目前已使用空间 (字节)

YGC :从应用程序启动到采样时年轻代中gc次数

YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)

-gcnewcapacity

年轻代对象的信息及其占用量

NGCMN :年轻代(young)中初始化(最小)的大小 (字节)

NGCMX :年轻代(young)的最大容量 (字节)

NGC :年轻代(young)中当前的容量 (字节)

S0CMX :年轻代中第一个survivor(幸存区)的最大容量 (字节)

S0C :年轻代中第一个survivor(幸存区)的容量 (字节)

S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)

S1C:年轻代中第二个survivor(幸存区)的容量 (字节)

ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)

EC:年轻代中Eden(伊甸园)的容量 (字节)

YGC:从应用程序启动到采样时年轻代中gc次数

FGC:从应用程序启动到采样时old代(全gc)gc次数

-gcold

old代对象的信息

MC :metaspace(元空间)的容量 (字节)

MU:metaspace(元空间)目前已使用空间 (字节)

CCSC:压缩类空间大小

CCSU:压缩类空间使用大小

OC:Old代的容量 (字节)

OU:Old代目前已使用空间 (字节)

YGC:从应用程序启动到采样时年轻代中gc次数

FGC:从应用程序启动到采样时old代(全gc)gc次数

FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

-gcoldcapacity

old代对象的信息及其占用量

OGCMN :old代中初始化(最小)的大小 (字节)

OGCMX :old代的最大容量 (字节)

OGC :old代当前新生成的容量 (字节)

OC :old代的容量 (字节)

YGC :从应用程序启动到采样时年轻代中gc次数

FGC :从应用程序启动到采样时old代(全gc)gc次数

FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

-gccause

下例显示了最近一次GC的原因,以及当前GC的原因:

LGCC:上次GC的原因

GCC:当前GC的原因

导出堆到文件jmap

jmap(JMemory Map)是 JDK 内置的命令行工具,核心作用是与 Java 进程的堆内存交互。可以生成堆转储快照(Dump 文件,二进制格式),用于离线分析内存泄漏、大对象占用、对象分布等问题;查看堆内存配置 / 使用情况、堆内对象统计、ClassLoader 信息、finalizer 队列等,是离线分析 JVM 堆内存的核心工具。

下例使用jmap生成PID为19080的Java程序的对象统计信息,并输出到 tomcat.txt 文件中:

bash 复制代码
jmap -histo 19080 >d:\tomcat.txt

可以看到,这个输出显示了内存中的实例数量和合计。

jmap 的另一个更为重要的功能是得到Java程序的当前堆快照:

bash 复制代码
jmap -dump:format=b,file=d:\analyzer\tomcat.hprof 19080

可以通过多种工具分析该堆文件,比如jhat工具,或者Visual VM、MAT等工具。这里使用 MAT 工具打开:

JDK自带堆分析工具 jhat

jhat(Java Heap Analysis Tool)是 JDK 内置的轻量级堆快照分析工具,专门用来解析 jmap 导出的 .hprof 格式堆 Dump 文件。它的核心原理是:将二进制的堆快照文件解析成结构化数据,然后启动一个本地 HTTP 服务器,可通过浏览器以可视化的方式查看堆内存的详细信息(比如对象分布、引用链、实例内容等),无需手动解析复杂的二进制文件。

bash 复制代码
jhat D:\analyzer\tomcat.hprof

jhat在分析完成后,使用HTTP服务器展示其分析结果,在浏览器中访问 http://127.0.0.1:7000

通过这些链接,开发者可以进一步查看所有类信息(包括Java平台的类)、所有类的实例数量以及实例的具体信息。

通常,导出的堆快照信息非常大,由于信息太多,可能很难通过页面上简单的链接索引找到想要的信息。为此,jhat还支持使用OQL语句对堆快照进行查询。使用OQL查询出当前Java程序中所有java.io.File 对象的路径:

select file.path.value.toString() from java.io.File file

可视化性能监控工具Visual VM

Visual VM(全称 VisualVM)是 JDK 内置的一款免费、开源的多合一可视化故障诊断与性能监控工具,从 JDK 6 Update 7 开始便作为 JDK 的标配组件发布,它的核心价值在于整合了 jps、jstat、jmap、jstack、jhat 等多款命令行工具的功能,并以图形化界面呈现,让开发者和运维人员无需记忆复杂的命令参数,就能直观地监控、分析 Java 应用的运行状态,甚至可以替代功能相对单一的 JConsole。

首先启动一个程序,我这里启动的是 tomcat 程序,双击 apache-tomcat-8.5.57\bin\startup.bat,再打开 jdk 的安装目录双击 C:\Program Files\Java\jdk1.8.0_261\bin\jvisualvm.exe

除了本地连接外,Visual VM 也支持远程JMX连接。

通过修改 Tomcat 启动脚本开启 JMX 远程连接,使得本地 VisualVM 能跨网络监控远程服务器上的 Tomcat 进程,操作流程如下;

打开 Tomcat 安装目录下的 bin/catalina.sh,加入如下启动参数

bash 复制代码
JAVA_OPTS="-Djava.rmi.server.hostname=123.56.146.124 \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.rmi.port=9999 \  
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false"

-Djava.rmi.server.hostname:用于指定远程服务器的 IP;

-Dcom.sun.management.jmxremote:开启 JMX 远程管理功能,基础开关;

-Dcom.sun.management.jmxremote.port=9999:用于指定 JMX 监听的端口,这个端口要在服务器防火墙中开放,避免被拦截;

-Dcom.sun.management.jmxremote.rmi.port=9999:固定 RMI 的数据传输端口,让 RMI 和 JMX 主端口共用 9999;

JMX 除了主端口,还会用 RMI 传输堆内存、线程等监控数据,默认 RMI 会用随机端口,防火墙无法提前开放,导致连接失败。

-Dcom.sun.management.jmxremote.authenticate:用于开启或关闭关闭 JMX 身份验证;

-Dcom.sun.management.jmxremote.ssl:用于开启或关闭 SSL 加密传输。

开放 9999 端口(需要注意的是 Tomcat 默认端口号为 8080,该端口号也要开启)


重启 Tomcat 使配置生效:

bash 复制代码
./shutdown.sh && ./startup.sh

下面进行远程连接,首先需要添加远程主机

远程主机右键点击添加JMX 连接...,输入对应的ip和端口号

监控概况

通过 Visual VM,可以查看应用程序的基本情况,比如进程ID、Main Class、启动参数等。

单击Tab页面上的监视页面,即可监控应用程序CPU、堆、永久区、类加载和线程数的总体情况,通过页面上的"执行垃圾回收"和"堆Dump"按钮还可以手工执行Full GC和生成堆快照,如图所示:

内存快照分析功能如图所示:

在顶部的Tab页中,提供了4个基本功能页:概要、类、实例和OQL控制台。

(1) 概要页面展示了当前内存的整体信息,包括内存大小、实例总数、类总数等。

(2) 在类页面中,以类为索引,显示了每个类的实例数占用空间。

(3) 在实例页面中,将显示指定类的所有实例。开发者便可以查看当前内存中,内存数据的实际内容。

(4) OQL控制台提供了更为强大的对象查询功能。有关VisualVM的OQL支持。

使用OQL查询出当前Java程序中所有java.io.File 对象的路径:

如果 Visual VM 在当前程序中找到死锁,则会以十分显眼的方式在线程页面给予提示,如以下死锁程序:

java 复制代码
import java.util.concurrent.locks.ReentrantLock;

public class DeadLock extends Thread {
    protected Object myDirect;
    static ReentrantLock south = new ReentrantLock();
    static ReentrantLock north = new ReentrantLock();

    public DeadLock(Object obj) {

        this.myDirect = obj;
        if (myDirect == south) {
            this.setName("south");
        }
        if (myDirect == north) {
            this.setName("north");
        }
    }

    @Override
    public void run() {
        if (myDirect == south) {
            try {
                north.lockInterruptibly();//占用north
                try {
                    Thread.sleep(500);//等待north启动
                } catch (Exception e) {
                    e.printStackTrace();
                }
                south.lockInterruptibly();//占用south
                System.out.println("car to south has passed");
            } catch (InterruptedException e1) {
                System.out.println("car to south is killed");

            } finally {
                if (north.isHeldByCurrentThread())
                    north.unlock();
                if (south.isHeldByCurrentThread())
                    south.unlock();
            }

        }

        if (myDirect == north) {
            try {
                south.lockInterruptibly();//占用south
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                north.lockInterruptibly();//占用north
                System.out.println("car to north has passed");
            } catch (InterruptedException e1) {
                System.out.println("car to north is killed");
            } finally {
                if (north.isHeldByCurrentThread())
                    north.unlock();
                if (south.isHeldByCurrentThread())
                    south.unlock();
            }

        }

    }

    public static void main(String[] args) throws InterruptedException {
        DeadLock car2south = new DeadLock(south);//2个线程死锁
        DeadLock car2north = new DeadLock(north);
        car2south.start();
        car2north.start();
        Thread.sleep(1000);
    }
}

Visual VM 有两个采样器,在"Sampler"页面下,显示了CPU和内存两个性能采样器,用于实时地监控程序信息。CPU采样器可以将CPU占用时间定位到方法,内存采样器可以查看当前程序的堆信息。

通过右键菜单中的"堆Dump"选项,可以立即获得当前应用程序的内存快照,如图所示(相当于jmap命令):


相关推荐
Scott9999HH4 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔4 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社5 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海5 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖6 小时前
JDK 26 新特性详解
java·开发语言
马优晨7 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区9 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大9 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai10 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说10 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json