Java-性能分析和监控工具深入详解

Java
337
0
0
2023-07-23
目录
  • Java监控和管理
  • Java监控和管理API
  • Java虚拟机的监控
  • Java监控和管理工具
  • JMC(Java Mission Control)
  • 启动JMC
  • JMC功能介绍
  • JFR(Java Flight Recorder)
  • 开启JFR记录
  • JConsole
  • 概述
  • JVisualVM

Java监控和管理

Java监控和管理API

Java Standard Edition(Java SE)平台提供的监控和管理技术 - JMX(Java Management Extensions) 技术。

Java SE 中包含了用于监控和管理的(java.lang.management)API,通过这些 API 可以实现应用程序的自我监控,此 API 主要提供了以下信息的访问:

  • 类加载相关。
  • JVM 相关,例如运行时间、系统环境变量、用户输入参数。
  • 线程相关,例如线程状态,线程的统计信息、线程的堆栈等。
  • 内存使用情况。
  • GC 情况。
  • 死锁检测。
  • 操作系统信息。

Java 8的java.lang.management模块:

ClassLoadingMXBean:用于 Java 虚拟机的类加载系统的管理接口。
CompilationMXBean:用于 Java 虚拟机的编译系统的管理接口。
GarbageCollectorMXBean:用于 Java 虚拟机的垃圾回收的管理接口。
MemoryManagerMXBean:内存管理器的管理接口。
MemoryMXBeanJava :虚拟机的内存系统的管理接口。
MemoryPoolMXBean:内存池的管理接口。
OperatingSystemMXBean:用于操作系统的管理接口,Java 虚拟机在此操作系统上运行。
RuntimeMXBeanJava :虚拟机的运行时系统的管理接口。
ThreadMXBeanJava :虚拟机线程系统的管理接口。

Java虚拟机的监控

上面说到 Java SE 中已经内置了开箱即用的监控和管理功能,通过这些功能可以实现程序的自我监测,Java 默认已经实现了对 Java 虚拟机相关信息的监测。

下面通过一个简单的示例,演示如何通过监控管理 API 获取系统信息、编译器信息、内存信息以及垃圾收集器信息。

 public static void main(String[] args) {

        showJvmInfo();
        showMemoryInfo();
        showSystem();
        showClassLoading();
        showCompilation();
        showThread();
        showGarbageCollector();
        showMemoryManager();
        showMemoryPool();
    }

    /**
     * Java 虚拟机的运行时系统
     */
    public static void showJvmInfo() {
        RuntimeMXBean rtMxBean = ManagementFactory.getRuntimeMXBean();
        System.out.println("Java 虚拟机的运行时系统(RuntimeMXBean):");
        System.out.println("jvm vendor:" + rtMxBean.getVmVendor());
        System.out.println("jvm name:" + rtMxBean.getVmName());
        System.out.println("jvm version:" + rtMxBean.getVmVersion());
        System.out.println("jvm bootClassPath:" + rtMxBean.getBootClassPath());
        System.out.println("jvm start time:" + rtMxBean.getStartTime());
        System.out.println("\n");
    }

    /**
     * Java 虚拟机的内存系统
     */
    public static void showMemoryInfo() {
        MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heap = memoryMxBean.getHeapMemoryUsage();
        System.out.println("Java 虚拟机的内存系统(MemoryMXBean):");
        System.out.println("Heap " + heap.toString());
        System.out.println(
                "Heap" +
                        " init:" + heap.getInit() + byteMb(heap.getInit()) +
                        " used:" + byteMb(heap.getUsed()) +
                        " committed:" + byteMb(heap.getCommitted()) +
                        " max:" + byteMb(heap.getMax()));
        System.out.println("\n");
    }

    private static String byteMb(long source) {
        return "(" + source / / 1024 + "mb)";
    }

    /**
     * Java 虚拟机在其上运行的操作系统
     */
    public static void showSystem() {
        OperatingSystemMXBean operatingSystemMxBean = ManagementFactory.getOperatingSystemMXBean();
        System.out.println("Java 虚拟机在其上运行的操作系统(OperatingSystemMXBean):");
        System.out.println("Architecture(操作系统架构): " + operatingSystemMxBean.getArch());
        System.out.println("Processors(Java虚拟机可用的处理器数): " + operatingSystemMxBean.getAvailableProcessors());
        System.out.println("System name(操作系统名称): " + operatingSystemMxBean.getName());
        System.out.println("System version(操作系统版本): " + operatingSystemMxBean.getVersion());
        System.out.println("Last minute load(最后一分钟的系统负载平均值): " + operatingSystemMxBean.getSystemLoadAverage());
        System.out.println("\n");
    }

    /**
     * Java 虚拟机的类加载系统
     */
    public static void showClassLoading() {
        ClassLoadingMXBean classLoadingMxBean = ManagementFactory.getClassLoadingMXBean();
        System.out.println("Java 虚拟机的类加载系统(ClassLoadingMXBean):");
        System.out.println("TotalLoadedClassCount(加载的类总数): " + classLoadingMxBean.getTotalLoadedClassCount());
        System.out.println("LoadedClassCount(当前加载的类的数量)" + classLoadingMxBean.getLoadedClassCount());
        System.out.println("UnloadedClassCount(卸载类的总数):" + classLoadingMxBean.getUnloadedClassCount());
        System.out.println("\n");
    }

    /**
     * Java 虚拟机的编译系统
     */
    public static void showCompilation() {
        CompilationMXBean compilationMxBean = ManagementFactory.getCompilationMXBean();
        System.out.println("Java 虚拟机的编译系统(CompilationMXBean):");
        System.out.println("TotalCompilationTime(编译时间(毫秒)):" + compilationMxBean.getTotalCompilationTime());
        System.out.println("name(JIT编译器的名称):" + compilationMxBean.getName());
        System.out.println("\n");
    }

    /**
     * Java 虚拟机的线程系统
     */
    public static void showThread() {
        ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
        System.out.println("Java 虚拟机的线程系统(ThreadMXBean):");
        System.out.println("ThreadCount(当前活动线程数)" + threadMxBean.getThreadCount());
        System.out.println("PeakThreadCount(峰值实时线程计数)" + threadMxBean.getPeakThreadCount());
        System.out.println("TotalStartedThreadCount(启动的线程总数)" + threadMxBean.getTotalStartedThreadCount());
        System.out.println("DaemonThreadCount(当前活动后台进程线程数)" + threadMxBean.getDaemonThreadCount());
        System.out.println("isSynchronizerUsageSupported(虚拟机是否支持监视可下载同步器的使用情况)" + threadMxBean.isSynchronizerUsageSupported());
        System.out.println("AllThreadIds(所有活动线程ID):" + JSON.toJSONString(threadMxBean.getAllThreadIds()));
        System.out.println("CurrentThreadUserTime(当前线程在用户模式下执行的CPU时间(以纳秒为单位))" + threadMxBean.getCurrentThreadUserTime());
        for (ThreadInfo threadInfo : threadMxBean.getThreadInfo(threadMxBean.getAllThreadIds(),)) {
            System.out.print(threadInfo.getThreadId() + threadInfo.toString());
        }
        System.out.println("\n");
    }

    /**
     * Java 虚拟机中的垃圾回收器。
     */
    public static void showGarbageCollector() {
        List<GarbageCollectorMXBean> collectorMxBeans = ManagementFactory.getGarbageCollectorMXBeans();
        System.out.println("Java 虚拟机中的垃圾回收器(GarbageCollectorMXBean):");
        for (GarbageCollectorMXBean collectorMxBean : collectorMxBeans) {
            System.out.println("name(垃圾收集器名称):" + collectorMxBean.getName());
            System.out.println("--CollectionCount:" + collectorMxBean.getCollectionCount());
            System.out.println("--CollectionTime" + collectorMxBean.getCollectionTime());
            System.out.println("\n");
        }
        System.out.println("\n");
    }

    /**
     * Java 虚拟机中的内存管理器
     */
    public static void showMemoryManager() {
        List<MemoryManagerMXBean> memoryManagerMxBeans = ManagementFactory.getMemoryManagerMXBeans();
        System.out.println("Java 虚拟机中的内存管理器(MemoryManagerMXBean):");
        for (MemoryManagerMXBean managerMxBean : memoryManagerMxBeans) {
            System.out.println("name(内存管理器名称):" + managerMxBean.getName());
            System.out.println("--MemoryPoolNames:" + String.join(",", managerMxBean.getMemoryPoolNames()));
            System.out.println("\n");
        }
        System.out.println("\n");
    }

    /**
     * Java 虚拟机中的内存池
     */
    public static void showMemoryPool() {
        List<MemoryPoolMXBean> memoryPoolMxBeans = ManagementFactory.getMemoryPoolMXBeans();
        System.out.println("Java 虚拟机中的内存池(MemoryPoolMXBean):");
        for (MemoryPoolMXBean memoryPoolMxBean : memoryPoolMxBeans) {
            System.out.println("name:" + memoryPoolMxBean.getName());
            System.out.println("--CollectionUsage:" + memoryPoolMxBean.getCollectionUsage());
            System.out.println("--type:" + memoryPoolMxBean.getType());
            System.out.println("\n");
        }
        System.out.println("\n");
    }
}

输出:

Java 虚拟机的运行时系统(RuntimeMXBean):
jvm vendor:Oracle Corporation
jvm name:Java HotSpot(TM)-Bit Server VM
jvm version:.221-b11
jvm bootClassPath:F:\opt\Java\jdk\jre\lib\resources.jar;F:\opt\Java\jdk8\jre\lib\rt.jar;F:\opt\Java\jdk8\jre\lib\sunrsasign.jar;F:\opt\Java\jdk8\jre\lib\jsse.jar;F:\opt\Java\jdk8\jre\lib\jce.jar;F:\opt\Java\jdk8\jre\lib\charsets.jar;F:\opt\Java\jdk8\jre\lib\jfr.jar;F:\opt\Java\jdk8\jre\classes
jvm start time:

Java 虚拟机的内存系统(MemoryMXBean):
Heap init =(262144K) used = 4028824(3934K) committed = 257425408(251392K) max = 3791650816(3702784K)
Heap init:(256mb) used:(3mb) committed:(245mb) max:(3616mb)

Java 虚拟机在其上运行的操作系统(OperatingSystemMXBean):
Architecture(操作系统架构): amd
Processors(Java虚拟机可用的处理器数):
System name(操作系统名称): Windows
System version(操作系统版本):.0
Last minute load(最后一分钟的系统负载平均值): -.0

Java 虚拟机的类加载系统(ClassLoadingMXBean):
TotalLoadedClassCount(加载的类总数):
LoadedClassCount(当前加载的类的数量)
UnloadedClassCount(卸载类的总数):

Java 虚拟机的编译系统(CompilationMXBean):
TotalCompilationTime(编译时间(毫秒)):
name(JIT编译器的名称):HotSpot-Bit Tiered Compilers

Java 虚拟机的线程系统(ThreadMXBean):
ThreadCount(当前活动线程数)
PeakThreadCount(峰值实时线程计数)
TotalStartedThreadCount(启动的线程总数)
DaemonThreadCount(当前活动后台进程线程数)
isSynchronizerUsageSupported(虚拟机是否支持监视可下载同步器的使用情况)true
AllThreadIds(所有活动线程ID):[,4,3,2,1]
CurrentThreadUserTime(当前线程在用户模式下执行的CPU时间(以纳秒为单位))
"Attach Listener" Id=5 RUNNABLE
"Signal Dispatcher" Id=4 RUNNABLE
"Finalizer" Id=3 WAITING on java.lang.ref.ReferenceQueue$Lock@17c68925
	at java.lang.Object.wait(Native Method)
	-  waiting on java.lang.ref.ReferenceQueue$Lock@c68925
"Reference Handler" Id=2 WAITING on java.lang.ref.Reference$Lock@7e0ea639
	at java.lang.Object.wait(Native Method)
	-  waiting on java.lang.ref.Reference$Lock@e0ea639
"main" Id=1 RUNNABLE
	at sun.management.ThreadImpl.getThreadInfo(Native Method)

Java 虚拟机中的垃圾回收器(GarbageCollectorMXBean):
name(垃圾收集器名称):PS Scavenge
--CollectionCount:
--CollectionTime

name(垃圾收集器名称):PS MarkSweep
--CollectionCount:
--CollectionTime

Java 虚拟机中的内存管理器(MemoryManagerMXBean):
name(内存管理器名称):CodeCacheManager
--MemoryPoolNames:Code Cache

name(内存管理器名称):Metaspace Manager
--MemoryPoolNames:Metaspace,Compressed Class Space

name(内存管理器名称):PS Scavenge
--MemoryPoolNames:PS Eden Space,PS Survivor Space

name(内存管理器名称):PS MarkSweep
--MemoryPoolNames:PS Eden Space,PS Survivor Space,PS Old Gen

Java 虚拟机中的内存池(MemoryPoolMXBean):
name:Code Cache
--CollectionUsage:null
--type:Non-heap memory

name:Metaspace
--CollectionUsage:null
--type:Non-heap memory

name:Compressed Class Space
--CollectionUsage:null
--type:Non-heap memory

name:PS Eden Space
--CollectionUsage:init =(65536K) used = 0(0K) committed = 0(0K) max = 1399848960(1367040K)
--type:Heap memory

name:PS Survivor Space
--CollectionUsage:init =(10752K) used = 0(0K) committed = 0(0K) max = 11010048(10752K)
--type:Heap memory

name:PS Old Gen
--CollectionUsage:init =(175104K) used = 0(0K) committed = 0(0K) max = 2843738112(2777088K)
--type:Heap memory

Disconnected from the target VM, address: '.0.0.1:12687', transport: 'socket'

Process finished with exit code

Java监控和管理工具

JMX 技术中提到 JMX 不仅提供了监控和管理的 API ,还提供了用于网络远程管理的服务,可以使用 JMX 相关监控管理工具,通过网络远程连接到正在运行 Java 虚拟机,监控其运行状态。

JMC(Java Mission Control)

Java Mission Control使您能够监视和管理Java应用程序,而不会引入通常与这些类型的工具相关联的性能开销。

它使用为Java虚拟机(JVM)的常规自适应动态优化收集的数据。

除了最小化性能开销之外,这种方法还消除了观察器效应的问题,当监视工具改变系统的执行特性时会发生这种问题。

Java Mission Control由客户端应用程序(JMC客户端)和在其上运行的许多插件组成:

  • JVM Browser显示正在运行的Java应用程序及其JVM。每个JVM实例都称为JVM连接。
  • JMX Console连接到正在运行的JVM,实时收集和显示其特征,并允许您通过Managed Beans(MBean)更改某些运行时属性。您还可以创建触发某些事件的规则(例如,如果应用程序的CPU使用率达到90%,则发送电子邮件)。
  • Java Flight Recorder(JFR)收集并保存详细的性能特征,以进行历史分析和分析。它可以用作独立的性能监视和分析工具,但是当用作JMC客户端的插件时,它会在逻辑分组的表,图表和拨号中显示诊断信息。它使您可以选择专注于问题所需的时间范围和详细程度。
  • Java Mission Control插件使用Java Management Extensions(JMX)代理连接到JVM。

启动JMC

双击JAvA_HOME\bin\jmc.exe 文件启动JMC

连接远程程序添加配置:

 -Dcom.sun.management.jmxremote.port=
 -Dcom.sun.management.jmxremote 
 -Dcom.sun.management.jmxremote.authenticate=false 
 -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=your ip

JMC功能介绍

MBean浏览器中查看类属性信息:

内存栏目查看GC、各个内存区域使用情况:

线程状态、死锁、堆栈信息:

诊断命令,查询vm信息等:

JFR(Java Flight Recorder)

黑匣子是用于记录飞机飞行和性能参数的仪器。在飞机出问题后,用于定位问题原因。JFR 就是 Java 的黑匣子。

JFR 是 Java Flight Record (Java飞行记录) 的缩写,是 JVM 内置的基于事件的JDK监控记录框架。

这个起名就是参考了黑匣子对于飞机的作用,将Java进程比喻成飞机飞行。

顾名思义,这个记录主要用于问题定位和持续监控。

如果是利用默认配置启动这个记录,性能非常高效,对于业务影响很小,因为这个框架本来就是用来长期在线上部署的框架。

这个记录可以输出成二进制文件,用户可以指定最大记录时间,或者最大记录大小,供用户在需要的时候输出成文件进行事后分析。

JFR在Java应用运行时收集对应发生的事件,主要有三种类型的事件提供给JFR收集:

  • 即时事件:一旦事件发生会立即进行数据记录
  • 持续事件:如果持续时间超过指定阈值则进行数据记录
  • 简单事件:用于记录应用所在系统的活跃指标(例如CPU,内存等)

开启JFR记录

通过启动参数配置并且启用 JFR,也可以通过启动参数在 JVM 进程启动的时候就启动 JFR,或者是利用 jcmd 工具,动态启用或者关闭 JFR。

JDK 8中的-XX:+FlightRecorder

java -XX:StartFlightRecording=disk=true,dumponexit=true,filename=recording.jfr,maxsize=m,maxage=1d,settings=profile,path-to-gc-roots=true test.Main

JConsole

Jconsole (Java Monitoring and Management Console),一种基于JMX的可视化监视、管理工具。

JConsole 基本包括以下基本功能:概述、内存、线程、类、VM概要、MBean。

概述

内存

线程

可以看到线程列表、线程状态、线程名称、线程堆栈等信息。

可以看到 已加装当前类、已加载类总数、已卸载类总数。

VM

MXBean

JVisualVM

VisualVM(All-in-One Java Troubleshooting Tool);功能最强大的运行监视和故障处理程序。

功能描述:

  • 显示虚拟机进程以及进程的配置环境信息(jps、jinfo)。
  • 监视应用程序的CPUGC方法区(1.7及以前),元空间(JDK1.8及以后)以及线程的信息(jstat、jstack)。
  • dump以及分析堆转储快照(jmap、jhat)。
  • 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法。
  • 离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立一个快照。

Java Management Extensions(JMX)