赞
踩
Java Standard Edition(Java SE)平台提供的监控和管理技术 - JMX(Java Management Extensions) 技术。
Java SE 中包含了用于监控和管理的(java.lang.management)API,通过这些 API 可以实现应用程序的自我监控,此 API 主要提供了以下信息的访问:
类名 | 描述 |
---|---|
ClassLoadingMXBean | 用于 Java 虚拟机的类加载系统的管理接口。 |
CompilationMXBean | 用于 Java 虚拟机的编译系统的管理接口。 |
GarbageCollectorMXBean | 用于 Java 虚拟机的垃圾回收的管理接口。 |
MemoryManagerMXBean | 内存管理器的管理接口。 |
MemoryMXBean | Java 虚拟机的内存系统的管理接口。 |
MemoryPoolMXBean | 内存池的管理接口。 |
OperatingSystemMXBean | 用于操作系统的管理接口,Java 虚拟机在此操作系统上运行。 |
RuntimeMXBean | Java 虚拟机的运行时系统的管理接口。 |
ThreadMXBean | 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() + byte2Mb(heap.getInit()) + " used:" + byte2Mb(heap.getUsed()) + " committed:" + byte2Mb(heap.getCommitted()) + " max:" + byte2Mb(heap.getMax())); System.out.println("\n"); } private static String byte2Mb(long source) { return "(" + source / 1024 / 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(), 1)) { 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) 64-Bit Server VM jvm version:25.221-b11 jvm bootClassPath:F:\opt\Java\jdk8\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:1673181328952 Java 虚拟机的内存系统(MemoryMXBean): Heap init = 268435456(262144K) used = 4028824(3934K) committed = 257425408(251392K) max = 3791650816(3702784K) Heap init:268435456(256mb) used:(3mb) committed:(245mb) max:(3616mb) Java 虚拟机在其上运行的操作系统(OperatingSystemMXBean): Architecture(操作系统架构): amd64 Processors(Java虚拟机可用的处理器数): 8 System name(操作系统名称): Windows 10 System version(操作系统版本): 10.0 Last minute load(最后一分钟的系统负载平均值): -1.0 Java 虚拟机的类加载系统(ClassLoadingMXBean): TotalLoadedClassCount(加载的类总数): 507 LoadedClassCount(当前加载的类的数量)507 UnloadedClassCount(卸载类的总数):0 Java 虚拟机的编译系统(CompilationMXBean): TotalCompilationTime(编译时间(毫秒)):8 name(JIT编译器的名称):HotSpot 64-Bit Tiered Compilers Java 虚拟机的线程系统(ThreadMXBean): ThreadCount(当前活动线程数)5 PeakThreadCount(峰值实时线程计数)5 TotalStartedThreadCount(启动的线程总数)5 DaemonThreadCount(当前活动后台进程线程数)4 isSynchronizerUsageSupported(虚拟机是否支持监视可下载同步器的使用情况)true AllThreadIds(所有活动线程ID):[5,4,3,2,1] CurrentThreadUserTime(当前线程在用户模式下执行的CPU时间(以纳秒为单位))234375000 5"Attach Listener" Id=5 RUNNABLE 4"Signal Dispatcher" Id=4 RUNNABLE 3"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@17c68925 2"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@7e0ea639 1"main" Id=1 RUNNABLE at sun.management.ThreadImpl.getThreadInfo1(Native Method) Java 虚拟机中的垃圾回收器(GarbageCollectorMXBean): name(垃圾收集器名称):PS Scavenge --CollectionCount:0 --CollectionTime0 name(垃圾收集器名称):PS MarkSweep --CollectionCount:0 --CollectionTime0 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 = 67108864(65536K) used = 0(0K) committed = 0(0K) max = 1399848960(1367040K) --type:Heap memory name:PS Survivor Space --CollectionUsage:init = 11010048(10752K) used = 0(0K) committed = 0(0K) max = 11010048(10752K) --type:Heap memory name:PS Old Gen --CollectionUsage:init = 179306496(175104K) used = 0(0K) committed = 0(0K) max = 2843738112(2777088K) --type:Heap memory Disconnected from the target VM, address: '127.0.0.1:12687', transport: 'socket' Process finished with exit code 0
JMX 技术中提到 JMX 不仅提供了监控和管理的 API ,还提供了用于网络远程管理的服务,可以使用 JMX 相关监控管理工具,通过网络远程连接到正在运行 Java 虚拟机,监控其运行状态。
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。
双击JAVA_HOME\bin\jmc.exe 文件启动JMC
连接远程程序添加配置:
-Dcom.sun.management.jmxremote.port=7001
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=your ip
MBean浏览器中查看类属性信息:
内存栏目查看GC、各个内存区域使用情况:
线程状态、死锁、堆栈信息:
诊断命令,查询vm信息等:
黑匣子是用于记录飞机飞行和性能参数的仪器。在飞机出问题后,用于定位问题原因。JFR 就是 Java 的黑匣子。
JFR 是 Java Flight Record (Java飞行记录) 的缩写,是 JVM 内置的基于事件的JDK监控记录框架。这个起名就是参考了黑匣子对于飞机的作用,将Java进程比喻成飞机飞行。顾名思义,这个记录主要用于问题定位和持续监控。
如果是利用默认配置启动这个记录,性能非常高效,对于业务影响很小,因为这个框架本来就是用来长期在线上部署的框架。这个记录可以输出成二进制文件,用户可以指定最大记录时间,或者最大记录大小,供用户在需要的时候输出成文件进行事后分析。
JFR在Java应用运行时收集对应发生的事件,主要有三种类型的事件提供给JFR收集:
通过启动参数配置并且启用 JFR,也可以通过启动参数在 JVM 进程启动的时候就启动 JFR,或者是利用 jcmd 工具,动态启用或者关闭 JFR。
JDK 8中的-XX:+FlightRecorder
java -XX:StartFlightRecording=disk=true,dumponexit=true,filename=recording.jfr,maxsize=1024m,maxage=1d,settings=profile,path-to-gc-roots=true test.Main
配置key | 默认值 | 说明 |
---|---|---|
delay | 0 | 延迟多久后启动 JFR 记录,支持带单位配置, 例如 delay=60s(秒), delay=20m(分钟), delay=1h(小时), delay=1d(天),不带单位就是秒, 0就是没有延迟直接开始记录。一般为了避免框架初始化等影响,我们会延迟 1 分钟开始记录(例如Spring cloud应用,可以看下日志中应用启动耗时,来决定下这个时间)。 |
disk | true | 是否写入磁盘,这个就是上文提到的, global buffer 满了之后,是直接丢弃还是写入磁盘文件。 |
dumponexit | false | 程序退出时,是否要dump出 .jfr文件 |
duration | 0 | JFR 记录持续时间,同样支持单位配置,不带单位就是秒,0代表不限制持续时间,一直记录。 |
filename | 启动目录/hotspot-pid-26732-id-1-2020_03_12_10_07_22.jfr,pid 后面就是 pid, id 后面是第几个 JFR 记录,可以启动多个 JFR 记录。最后就是时间。 | dump的输出文件 |
name | 无 | 记录名称,由于可以启动多个 JFR 记录,这个名称用于区分,否则只能看到一个记录 id,不好区分。 |
maxage | 0 | 这个参数只有在 disk 为 true 的情况下才有效。最大文件记录保存时间,就是 global buffer 满了需要刷入本地临时目录下保存,这些文件最多保留多久的。也可以通过单位配置,没有单位就是秒,默认是0,就是不限制 |
maxsize | 250MB | 这个参数只有在 disk 为 true 的情况下才有效。最大文件大小,支持单位配置, 不带单位是字节,m或者M代表MB,g或者G代表GB。设置为0代表不限制大小**。虽然官网说默认就是0,但是实际用的时候,不设置会有提示**: No limit specified, using maxsize=250MB as default. 注意,这个配置不能小于后面将会提到的 maxchunksize 这个参数。 |
path-to-gc-roots | false | 是否记录GC根节点到活动对象的路径,一般不打开这个,首先这个在我个人定位问题的时候,很难用到,只要你的编程习惯好。还有就是打开这个,性能损耗比较大,会导致FullGC一般是在怀疑有内存泄漏的时候热启动这种采集,并且通过产生对象堆栈无法定位的时候,动态打开即可。一般通过产生这个对象的堆栈就能定位,如果定位不到,怀疑有其他引用,例如 ThreadLocal 没有释放这样的,可以在 dump 的时候采集 gc roots |
settings | 默认是 default.jfc,这个位于 $JAVA_HOME/lib/jfr/default.jfc | 采集 Event 的详细配置,采集的每个 Event 都有自己的详细配置。另一个 JDK 自带的配置是 profile.jfc,位于 $JAVA_HOME/lib/jfr/profile.jfc 。这个配置文件里面的配置是怎么回事,我们后面会涉及。 |
感兴趣可以看看:
https://juejin.cn/post/6959405798556434440
https://zhuanlan.zhihu.com/p/87850586
Jconsole (Java Monitoring and Management Console),一种基于JMX的可视化监视、管理工具。
JConsole 基本包括以下基本功能:概述、内存、线程、类、VM概要、MBean。
可以看到线程列表、线程状态、线程名称、线程堆栈等信息。
可以看到 已加装当前类、已加载类总数、已卸载类总数。
VisualVM(All-in-One Java Troubleshooting Tool);功能最强大的运行监视和故障处理程序。
功能描述:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。