性能监控工具-JDK性能监控

性能监控工具-JDK性能监控JDK 性能监控工具 jdk 开发包中 除了比较熟悉的 java exe javac exe 还有一系列的辅助工具 它们都存放在 jdk 安装目录 bin 目录下 乍一看这些都是 exe 但实际上它们只是将 java 程序的一层包装 真正的实现是在 lib tools jar 中 以 jps 命令为例 它实质上是运行 java classpath JAVA HOME lib tools jarsun

实战java虚拟机


JDK性能监控工具

jdk开发包中,除了比较熟悉的java.exe,javac.exe,还有一系列的辅助工具,它们都存放在jdk安装目录/bin目录下,乍一看这些都是exe,但实际上它们只是将java程序的一层包装,真正的实现是在lib/tools.jar中。以jps命令为例,它实质上是运行:

java -classpath $JAVA_HOME/lib/tools.jar sun.tools.jps.Jps 

查看Java进程——jps命令

这里写图片描述

查看虚拟机运行时信息——jstat命令

  • option
    • -class: 显示classLoader的相关信息
    • -compiler: 显示JIT(Just-In-Time Compiler即时编译器)的相关信息
    • -gc: 显示与gc相关堆信息
    • -gccapacity: 显示各代的容量以及使用情况
    • -gccause: 显示垃圾收集相关信息(同 -gcutil),显示最后一次或当前发生的垃圾收集的诱发原因
    • -gcnew: 显示新生代信息
    • -gcnewcapacity: 显示新生代大小与使用情况
    • -gcold :
    • -gcoldcapacity
    • -gcpermcapacity: 显示永久代的大小 –jdk8之后变更为 -gcmetacapacity
    • -gcutil: 显示垃圾收集信息(百分比%)
    • -printcompilation: 输出JIT编译的方法信息
  • -t: 在输出的信息前加上一个timestamp列,显示程序运行的时间(s)
  • -h: 在周期性输出时,输出多少行后,跟着输出一个表头信息
  • interver:用于指定输出统计数据的周期,单位是毫秒
  • count: 用于统计输出多少次数据;
    这里写图片描述


-class

Loaded Bytes Unloaded Bytes Time 1546 2835.7 0 0.0 2.06 //loaded 载入类的数量 //Bytes 载入类的合计大小 //Unloaded 卸载类的数量 //第二个bytes 卸载类的合计大小 //time 加载和卸载的时间之和 

-compiler

Compiled Failed Invalid Time FailedType FailedMethod 847 0 0 1.28 0 //Compiled 编译任务执行的次数, //Failed 编译失败的次数, //Invalid 编译不可用次数 //FailedType 最后一次失败的类型 //FailedMethod 最后一次失败的类名和方法名 

-gc

 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 5120.0 5120.0 2208.0 0.0 63488.0 54658.8 84992.0 24.0 8832.0 8388.6 1152.0 984.5 4 0.021 0 0.000 0.021 //S01,S1C,S0U,S1U from,to的大小和已用量大小(KB) //EC,EU eden的大小和已用量 //OC,OU 老边代的大小和已用量 //PC,PM 永久区大小和已用量 --- JDK8之后变为 // MC,MU ,元数据区大小和已用量 //CCSC,CCSU 压缩类空间大小和已用量 --- //YGC,YGCT: 新生代GC次数和耗时 //FGC,FGCT: Full GC次数和耗时 //GCT GC总耗时 

-gccapacity

 NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC 41984.0 .0 73728.0 5120.0 5120.0 63488.0 84992.0 .0 84992.0 84992.0 0.0 .0 8832.0 0.0 .0 1152.0 4 0 //NGCMN ,NGCMX : 新生代最小值和最大值(KB) //MN:表示最小 ,MX表示最大 

-gccause

 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC 42.81 0.00 86.20 0.05 95.00 85.50 4 0.018 0 0.000 0.018 Allocation Failure No GC //LGCC 上次GC原因 //GCC 本次GC原因 

-gcnew

 S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT 5120.0 5120.0 2208.0 0.0 7 15 5120.0 63488.0 54658.8 4 0.021 //TT 新生代晋升到老年代年龄 //MTT 新生代晋升到老年代最大年龄 //DSS 所需的survivor区大小 

查看虚拟机参数——jinfo命令

jinfo可以用来查看正在运行的java应用程序的扩展参数,甚至支持在运行时,修改部分参数,它的基本语法为:jinfo [option]
它的option值可以为:

  • -flag 打印指定虚拟机参数[name]的值
  • -flag [+|-] to enable or disable the named VM flag
  • -flag = to set the named VM flag to the given value
  • -flags to print VM flags
  • -sysprops to print Java system properties

  • 默认为以上所有的操作

- flags : 如-XX:NewSize,-XX:OldSize等虚拟机相关参数.
- sysprops :java.class.path,java.vm.info等…

这里写图片描述


导出堆到文件——jmap命令

jmap命令是一个多功能命令。它可以生成Java程序的堆Dump文件,也可以查看堆内对象实例的统计信息、查看ClassLoader的信息以及finalizer队列。它的命令格式:

jmap [option] 
           
             (to connect to running process) jmap [option] 
            
              (to connect to a core file) jmap [option] [server_id@] 
             
               (to connect to remote debug server) 
              
             
           

option选项有如下:

  • -heap 打印Java堆详细信息
  • -histo[:live] 显示堆中对象的统计信息,如果使用了:live子属性,则只统计“存活”对象。
  • -clstats 打印类加载器的统计信息(取代了在JDK8之前的 -permstat)
  • -permstat Java堆内存的永久保存区域的类加载器的统计信息 —-JDK8之后无此选项
  • -finalizerinfo 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
  • -dump: 生成堆转储快照
  • -F 当-dump没有响应时,强制生成dump快照
  • -J 传递参数给jmap启动的jvm

-histo
统计9336号进程的存活对象统计信息,并保存到文件:$ jmap -histo:live 9336 >d:/dum02.txt,结果如下图:
这里写图片描述
,结果中统计了内存中实例对象数和合计。






-dump
-dump功能得到java程序的当前堆快照:jmap -dump:format=b,file=d:/heamp.hprof 8996

-clstats 与 permstat
该命令还可以查看系统的classloader信息,以及classloader的父子关系,以及各个classloader内部加载的类的数量和总大小。$ jmap -clstats 7876
这里写图片描述




-finalizerinfo
可以观察系统中finalizer队列中的对象,一个不恰当的finalize()方法可能导致对象堆积在finalizer队列里。$ jmap -finalizerinfo 7876
这里写图片描述
,上图的finalizer队列长度为0。







JDK自带的堆分析工具——jhat

使用jhat工具可以分析java应用程序的堆快照内容:$ jhat d:/heap.hprof
这里写图片描述
,分析的结果通过浏览器 localhost:7000查看。
这里写图片描述







查看线程堆栈信息——jstack

jstack可以打印出java程序的线程堆栈信息。jstack [option]

option选项信息:

  • -F 强制解析线程dump,当程序已经挂起使用
  • -m (mixed model)打印java方法和本地方法
  • -l 增加打印锁的信息

下例为一个死锁程序,java程序代码如下:

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(); Thread.sleep(500); south.lockInterruptibly(); System.out.println("car to south has passed"); } catch (InterruptedException e) { e.printStackTrace(); 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(); Thread.sleep(500); north.lockInterruptibly(); System.out.println("car to north has passed"); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("car to north is killed"); } finally { if(south.isHeldByCurrentThread()) { south.unlock(); } if(north.isHeldByCurrentThread()) { north.unlock(); } } } } public static void main(String[] args) throws InterruptedException { DeadLock car2south = new DeadLock(south); DeadLock car2north = new DeadLock(north); car2south.start(); car2north.start(); Thread.sleep(1000); } } 

使用命令jstak -l pid >d:/dead.txt 打印结果:

"north" prio=6 tid=0x00000000069ad000 nid=0x2bcc waiting on condition [0x000000000792f000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007d6e54508> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:867) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1201) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312) at cn.jhs.chap05.DeadLock.run(DeadLock.java:50) Locked ownable synchronizers: - <0x00000007d6e544d8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) "south" prio=6 tid=0x000000000699c800 nid=0x1ed0 waiting on condition [0x000000000782f000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007d6e544d8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:867) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1201) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312) at cn.jhs.chap05.DeadLock.run(DeadLock.java:31) Locked ownable synchronizers: - <0x00000007d6e54508> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) //省略输出。。。。。 Found one Java-level deadlock: ============================= "north": waiting for ownable synchronizer 0x00000007d6e54508, (a java.util.concurrent.locks.ReentrantLock$NonfairSync), which is held by "south" "south": waiting for ownable synchronizer 0x00000007d6e544d8, (a java.util.concurrent.locks.ReentrantLock$NonfairSync), which is held by "north" Java stack information for the threads listed above: =================================================== //省略输出。。。。。 Found 1 deadlock. 

远程主机——jstat

它的命令格式:usage: jstatd [-nr] [-p port] [-n rminame]
option选项:

  • -nr 当一个存在的RMI Registry没有找到时,不尝试创建一个内部的RMI Registry
  • -p port 端口号,默认为1099
  • -n rminame 默认为JStatRemoteHost;如果多个jstatd服务开始在同一台主机上,rminame唯一确定一个jstatd服务
  • -J 公共jvm参数,可以为jps等命令本身设置其java虚拟机参数。

直接运行jstatd命令会报错,这是因为没有足够的权限所致。可以使用java的安全策略,为其分配相应的权限,并命名为all.policy

grant codebase "file:${JAVA_HOME}\lib\tools.jar" { permission java.security.AllPermission; }; 

使用命令:jstatd -J-Djava.security.policy=all.policy 服务即开启,默认端口1099。jstatd更为详尽的配置
使用jsp.jstat命令即可访问远程服务器的信息。

jps localhost:1099; jstat -gcutil 460@localhost:1099 //----460为进程号 

多功能命令行——jcmd命令

也可是使用:jcmd Mainclass来替代jcmd pid;

虚拟机信息如下: 9196 org.jetbrains.idea.maven.server.RemoteMavenServer ====================================================== $ jcmd 9196 help 等价于 $ jcmd org.jetbrains.idea.maven.server.RemoteMavenServer help 

jcmd拥有jmap大部分功能,并且Oracle官方也推荐使用jcmd替代jmap.


性能统计工具——hprof

HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)
与之前的监控工具不同,hprof不是独立的监控工具,它是一个java agent工具。它可以用于监控java应用程序在运行时的CPU和堆信息。使用java agentlib:hprof=help命令可以查看hprof的帮助文档。

Option Name and Value Description Default --------------------- ----------- ------- heap=dump|sites|all heap profiling all cpu=samples|times|old CPU usage off monitor=y|n monitor contention n format=a|b text(txt) or binary output a file= 
                 
                   write data to file java.hprof[{.txt}] net= 
                  
                    : 
                   
                     send data over a socket off depth= 
                    
                      stack trace depth 4 interval= 
                     
                       sample interval in ms 10 cutoff= 
                      
                        output cutoff point 0.0001 lineno=y|n line number in traces? y thread=y|n thread in traces? n doe=y|n dump on exit? y msa=y|n Solaris micro state accounting n force=y|n force output to 
                       
                         y verbose=y|n print messages about dumps y 
                        
                       
                      
                     
                    
                   
                 
  • java -agentlib:hprof=cpu=times,interval=10 xxx times选项记录java函数调用前后记录的时间,进而计算函数的执行时间。在当前程序目录下会生成java.hprof.txt文件,记录了性能统计信息。
  • java -agentlib:hprof=heap=dump,format=b,file=d:/x.hprof xx 将应用程序的堆快照保存在指定文件。
  • java -agentlib:hprof=heap=sites xxx 可以输出java应用程序中每个跟踪点上的类所占内存的百分比

图形化虚拟机监控工具JConsole

-Djava.rmi.server.hostname=127.0.0.1 //---ipv4地址是:192.1.217.111 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8889 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false 
  • 概览:以折线图的形式展示了堆内存,线程,类,CPU的使用情况。
  • 内存:不仅展示了堆内存的整体信息,更细化到Eden,Survivor,老年代的使用情况。同事也包括非堆区,Perm的使用情况。还提供了一个“执行GC”按钮,可以强制应用程序执行Full GC.
  • 线程:监视应用程序中线程信息,选中线程还可以跟踪线程的堆栈信息,同时还提供了“检测死锁”功能按钮
    这里写图片描述

  • :显示应用程序已加载和已卸载的类信息。
  • VM概述:展示当前应用程序的运行环境,包括虚拟机类型,版本,虚拟机参数,堆信息等。

可视化性能监控工具Visual VM

连接应用程序
Visual VM支持多种方式连接应用程序:

  • 本地连接: 在本地计算机正在运行的java程序。
  • 远程连接: 支持jmx和jstatd方式操作远程连接。具体的配置方式前文都已介绍到。

监控应用程序
选中了应用程序之后,即可看到监控的页面如下图:
这里写图片描述




  • 概览:主要包含了进程ID,MainClass,启动参数;JVM参数和系统属性等信息。
  • 监视:主要包含了CPU,内存(堆,Perm),类,线程的使用情况折线图。还提供了“执行垃圾回收”和“堆Dump”按钮来强制执行Full GC和生成堆快照文件。
  • 线程:提供线程的详细信息,还可以检测到死锁,提供“线程Dump”按钮,相当于执行jstack,导出当前线程的信息
    这里写图片描述

  • 抽样器:它有CPU和内存两个性能采样器,用于实时的监控程序信息。根据这个功能可以简单的定位到系统中最消耗资源的函数。
    这里写图片描述

  • profiler

Visual VM 的 BTrace插件(略)
BTrace是一款非常有意思的工具,它可以在不停机的情况下,通过字节码注入动态的监控系统的运行情况,它可以跟踪方法的调用,构造函数调用和系统内存等信息。


虚拟机诊断工具Mission Control

在Oracle收购sun之前,Oracle的JRockit虚拟机提供了一款JRockit Mission Control的虚拟机诊断工具。在收购sun之后,Oracle拥有了Sun Hotspot 和JRockit两款虚拟机,根据Oracle的战略,在JDK7 Update 40之后,将MissionControl集成到了Hotspot中。它位于$JAVA_HOME/bin/jmc.exe.

MBean服务器
这里写图片描述

飞行记录器(Flight Recorder)
它通过记录程序在一段时间内的运行情况,将记录结果进行分析和展示,可以进一步对系统的性能进行分析和诊断。要使用飞行记录器,对于要监控的程序必须添加参数:

-XX:+UnlockCommercialFeatures -XX:+FlightRecorder 

这里写图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/177582.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午7:10
下一篇 2026年3月26日 下午7:11


相关推荐

  • HTML5开发工具介绍-HBuilder[通俗易懂]

    HTML5开发工具介绍-HBuilder[通俗易懂]第一步:打开谷歌浏览器,在百度上搜索HBuilder。第二步:进入网站,选择下载HBuilderX。第三步:打开HBuilder,文件-新建-项目。第四步:选择普通项目-基本HTML项目-创建。第五步:基础的界面如下。…

    2022年7月15日
    21
  • 程序员写个人技术博客的价值与意义

    程序员写个人技术博客的价值与意义文章目录什么是博客主要用途博客分类个人博客使用第三方平台个人博客与独立博客的优缺点使用第三方平台个人博客的优点独立博客的优点没写博客的原因浪费时间工作太忙,没时间写懒于思考,疏于总结怕自己的技术被别人学到,被别人超越想写,但不知道写什么技术含量低,写出来没意义,怕别人嘲笑写博客最初的想法写博客的价值与意义加深对技术点的理解,记录足迹,反映成长,分类检索,方便日后查阅观点碰撞,分享收获结交更多志同道…

    2022年5月20日
    39
  • 关机程序(C语言)

    关机程序(C语言)分享一个小小的关机程序,可你发送给你的好友哦!!!#include<stdio.h>#include<string.h>//strcmp()#include<st

    2022年7月4日
    29
  • MongoDB和MySQL和Redis的区别

    MongoDB和MySQL和Redis的区别MongoDB和MySQL和Redis的区别MySQL1、在不同的引擎上有不同的存储方式。2、查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。3、开源数据库的份额在不断增加,mysql的份额页在持续增长。4、缺点就是在海量数据处理的时候效率会显著变慢。MongoDBMongodb是非关系型数据库(nosql),属于文档型数据库。文档是mongoDB中数据的基本单元,类似关系数据库的行,多个键值对有序地放置在一起便是文档,语法有点类似javascript面向对象的查询语言,

    2022年6月26日
    27
  • plsqldev中查看表结构「建议收藏」

    plsqldev中查看表结构「建议收藏」plsqldev中查看表结构通常情况下,可以使用desc表名来查看表结构但在plsqldev中不能使用desc命令在plsqldev工具中的sqlwindows区域Oracle的SQL缓冲区一次只能存放一条SQL命令而且SQL*PLUS附加命令不能在SQL里运行:但是,如果使用sqlplus就可以使用desc查看,

    2022年4月25日
    67
  • getParameterValues使用

    getParameterValues使用request.getParameterValues:接收名字相同,值有多个的变量,返回一个数据。如: String[]courseNumbers=request.getParameterValues(“courseNumberForCourse”);request.getParameter:接收单一值变量。如:stringtype=request.getPara

    2022年7月22日
    20

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号