性能监控工具

性能监控工具

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命令):


相关推荐
烤麻辣烫1 小时前
java进阶--刷题与详解-2
java·开发语言·学习·intellij-idea
Chan162 小时前
【 微服务SpringCloud | 方案设计 】
java·spring boot·微服务·云原生·架构·intellij-idea
小屁猪qAq2 小时前
设计模式总纲
开发语言·c++·设计模式
不绝1912 小时前
C#核心:多态
开发语言·c#
Howrun7772 小时前
C++标准线程库-全面讲解
开发语言·c++
浪扼飞舟2 小时前
C#(多线程和同步异步)
java·开发语言
万行2 小时前
机器人系统SLAM讲解
开发语言·python·决策树·机器学习·机器人
抬头望远方2 小时前
【无人机】无人机群在三维环境中的碰撞和静态避障仿真(Matlab代码实现)
开发语言·支持向量机·matlab·无人机
matlab科研助手2 小时前
【路径规划】基于遗传算法的农药无人机在多边形区域的路径规划研究附Matlab代码
开发语言·matlab·无人机