文章目录
- 第1章、概述
 - 第2章、jps:查看正在运行的Java进程
 - 第3章、jstat:查看JVM统计信息
 - 第4章、jinfo:实时查看和修改JVM配置参数
 - 第5章、jmap:导出内存映像文件&内存使用情况
 - 第6章、jhat:JDK自带堆分析工具
 - 第7章、jstack:打印JVM中线程快照
 - 第8章、jcmd:多功能命令行
 - 第9章、jstatd:远程主机信息收集
 
第1章、概述
- 性能诊断是软件工程师在日常工作中需要经常面对和解决的问题,在用户体验至上的今天,解决好应用的性能问题能带来非常大的收益
 - Java 作为最流行的编程语言之一,其应用性能诊断一直受到业界广泛关注。可能造成 Java 应用出现性能问题的因素非常多,例如线程控制、磁盘读写、数据库访问、网络I/O、垃圾收集等。想要定位这些问题,一款优秀的性能诊断工具必不可少
 - 体会1:使用数据说明问题,使用知识分析问题,使用工具处理问题
 - 体会2:无监控、不调优!
 
1、简单命令行工具
-  
进入到安装jdk的bin目录,发现还有一系列辅助工具
 -  
这些辅助工具用来获取目标 JVM 不同方面、不同层次的信息,帮助开发人员很好地解决Java应用程序的一些疑难杂症
 -  
官方源码地址:http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/jdk.jcmd/share/classes/sun/tools
 
第2章、jps:查看正在运行的Java进程
1、基本情况
- jps(Java Process Status):显示指定系统内所有的HotSpot虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程
 - 说明:对于本地虚拟机进程来说,进程的本地虚拟机ID与操作系统的进程ID是一致的,是唯一的
 
2、基本语法
- 基本使用语法为:jps [options] [hostid]
 - 还可以通过追加参数,来打印额外的信息
 - 可以通过 jps -help 来查看对应的参数信息
 
【1】options参数
-  
-q:仅仅显示LVMID(local virtual machine id),即本地虚拟机唯一id。不显示主类的名称等
 -  
-l:输出应用程序主类的全类名 或 如果进程执行的是jar包,则输出jar完整路径
 -  
-m:输出虚拟机进程启动时传递给主类main()的参数
 -  
-v:列出虚拟机进程启动时的JVM参数。比如:-Xms20m -Xmx50m是启动程序指定的jvm参数
 -  
注:
- 以上参数可以综合使用
 - 如果某 Java 进程关闭了默认开启的UsePerfData参数(即使用参数-XX:-UsePerfData),那么jps命令(以及下面介绍的jstat)将无法探知该 Java 进程
 
 -  
如何将信息输出到同级文件中:【语法:命令 > 文件名称】
 
【2】hostid参数
- RMI注册表中注册的主机名。如果想要远程监控主机上的 java 程序,需要安装 jstatd
 - 对于具有更严格的安全实践的网络场所而言,可能使用一个自定义的策略文件来显示对特定的可信主机或网络的访问,尽管这种技术容易受到IP地址欺诈攻击
 - 如果安全问题无法使用一个定制的策略文件来处理,那么最安全的操作是不运行jstatd服务器,而是在本地使用jstat和jps工具
 
第3章、jstat:查看JVM统计信息
1、简介
- jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据
 - 在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。常用于检测垃圾回收问题以及内存泄漏问题
 - 官方文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html
 
2、基本语法
- 基本使用语法为:jstat - [-t] [-h] [ []]
 - 查看命令相关参数:jstat-h 或 jstat-help
 - 其中vmid是进程id号,也就是jps之后看到的前面的号码
 

【1】option参数
-  
选项option可以由以下值构成
 -  
类装载相关的:
-  
-class:显示ClassLoader的相关信息:类的装载、卸载数量、总空间、类装载所消耗的时间等
-  
-class举例:jstat -class -t -h3 13152 1000 10,其中h3中的3代表每隔3个分隔一次,13152代表类的进程id,1000代表每隔1000毫秒打印一次,10代表一共打印10次,如下所示:
- Timestamp代表程序至今的运行时间,单位为秒
 - Loaded代表加载的类的数目
 - Bytes代表加载的类的总字节数
 - Unloaded代表卸载的类的数目
 - Bytes代表卸载的类的总字节数
 - Time代表类装载所消耗的时间
 

 
 -  
 
 -  
 -  
垃圾回收相关的:
-  
【1】-gc:显示与GC相关的堆信息。包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息
-  
-gc举例:jstat -gc 13152,其中13152代表类的进程id,执行结果如下所示:
- 其中S0C代表幸存者0区的总容量,S1C代表幸存者1区的总容量,S0U代表幸存者0区使用的容量,S1U代表幸存者1区使用的容量,EC代表伊甸园区的总容量,EU代表伊甸园区使用的总容量
 - OC代表老年代的总容量,OU代表老年代已经使用的容量,MC代表方法区的总容量,MU代表方法区的总容量,CCSC代表压缩类的总容量,CCSU代表压缩类使用的容量
 - YGC代表年轻代垃圾回收的次数,YGCT年轻代进行垃圾回收需要的时间,FGC代表代表Full GC的次数,FGCT代表Full GC的时间,GCT代表垃圾回收的总时间
 

 
 -  
 -  
【2】-gccapacity:显示内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-  
-gccapacity举例:jstat -gccapacity 13152,其中13152代表类的进程id,执行结果如下:
- S0C代表幸存者0区的容量,S1C代表幸存者1区的容量,EC代表伊甸园区的容量,CCSC代表压缩类的容量,YGC代表年轻代垃圾回收的时间,FGC代表Full GC垃圾回收的时间
 

 
 -  
 -  
【3】-gcutil:显示内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-  
-gcutil举例:jstat -gcutil 13152,其中13152代表类的进程id,执行结果如下所示:
- 以下是各区域占比以及垃圾回收的情况,S0代表幸存者0区,S1代表幸存者1区,E代表伊甸园区,O代表老年代,M代表方法区,CCS代表压缩类
 - 以下这些值都是占比情况,YGC代表年轻代垃圾回收的次数,YGCT年轻代进行垃圾回收需要的时间,FGC代表代表Full GC的次数,FGCT代表Full GC的时间,GCT代表垃圾回收的总时间
 

 
 -  
 -  
【4】-gccause:与-gcutil功能一样,但是会额外输出导致最后一次或当前正在发生的GC产生的原因
-  
-gccause举例:jstat -gccause 13152,其中13152代表类的进程id,执行结果如下:
- 以下是各区域占比以及垃圾回收的情况,还有触发垃圾回收的原因解释,S0代表幸存者0区,S1代表幸存者1区,E代表伊甸园区,O代表老年代,M代表方法区,CCS代表压缩类,以上这些值都是占比情况,YGC代表年轻代垃圾回收的次数,YGCT年轻代进行垃圾回收需要的时间,FGC代表代表Full GC的次数,FGCT代表Full GC的时间,GCT代表垃圾回收的总时间,LGCC和GCC代表垃圾回收的原因
 

 
 -  
 -  
【5】-gcnew:显示新生代GC状况
 -  
【6】-gcnewcapacity:显示内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
 -  
【7】-geold:显示老年代GC状况
 -  
【8】-gcoldcapacity:显示内容与-gcold基本相同,输出主要关注使用到的最大、最小空间
 -  
【9】-gcpermcapacity:显示永久代使用到的最大、最小空间
 
 -  
 -  
JIT相关的:
-  
-compiler:显示JIT编译器编译过的方法、耗时等信息
 -  
-printcompilation:输出已经被JIT编译的方法
 
 -  
 
【2】interval参数
- 用于指定输出统计数据的周期,单位为毫秒。即:查询间隔
 
【3】count参数
- 用于指定查询的总次数
 
【4】-t参数
-  
可以在输出信息前加上一个Timestamp列,显示程序的运行时间。单位:秒
 -  
补充:
-  
我们可以比较Java 进程的启动时间以及总 GC时间(GCT列),或者两次测量的间隔时间以及总GC时间的增量,来得出GC时间占运行时间的比例
 -  
如果该比例超过 20%,则说明目前堆的压力较大;如果该比例超过90%,则说明堆里几乎没有可用空间,随时都可能抛出OOM异常
 -  
执行jstat -gc -t 13152 1000 10,这代表1秒打印出1行,一共10行,-t代表打印出Timestamp总运行时间,结果如下所示:

 -  
上方红色框框中代表Timestamp,而蓝色框框中代表垃圾回收时间,单位都是秒,如果让红色框框中的某两个值相减,假设这个值是num1,然后让对应行的蓝色框框中的另外两个值相减,假设这个值是num2,之后让num2/num1,得出的差值就是上述所说的GC时间占运行时间的比例
 -  
虽然这种方式比较繁琐,但是在项目部署之后就需要使用命令行去看了,就没有可视化界面了,所以这种方式也要会
 
 -  
 
【5】-h参数
- 可以在周期性数据输出时,输出多少行数据后输出一个表头信息
 
3、补充
- jstat还可以用来判断是否出现内存泄漏
 - 第1步: 
  
- 在长时间运行的 Java程序中,我们可以运行jstat命令连续获取多行性能数据,并取这几行数据中OU列(即已占用的老年代内存)的最小值
 - 可以执行命令:jstat -gc -t 13152 1000 10
 
 - 第2步: 
  
- 然后,我们每隔一段较长的时间重复一次上述操作,来获得多组OU最小值。如果这些值呈上涨趋势,则说明该Java程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏
 
 
第4章、jinfo:实时查看和修改JVM配置参数
1、基本情况
- jinfo(Configuration Info for Java)
 - 查看虚拟机配置参数信息,也可用于调整虚拟机的配置参数。
 - 在很多情况下,Java应用程序不会指定所有的Java虚拟机参数。而此时,开发人员可能不知道某一个具体的Java虚拟机参数的默认值。在这种情况下,可能需要通过查找文档获取某个参数的默认值。这个查找过程可能是非常艰难的。但有了jinfo工具,开发人员可以很方便地找到ava虚拟机参数的当前值
 - https://docs.oracle.com/en/java/javase/11/tools/jinfo.html
 
C:\Users\AlphonseKino>jinfo
Usage:
    jinfo [option] <pid>
        (to connect to running process)
    jinfo [option] <executable <core>
        (to connect to a core file)
    jinfo [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)
where <option> is one of:
    -flag <name>         to print the value of the named VM flag
    -flag [+|-]<name>    to enable or disable the named VM flag
    -flag <name>=<value> to set the named VM flag to the given value
    -flags               to print VM flags
    -sysprops            to print Java system properties
    <no option>          to print both of the above
    -h | -help           to print this help message
 
2、基本语法
- 基本使用语法:jinfo [options] pid
 - java进程ID必须加上
 
| 选项 | 选项说明 | 
|---|---|
| no option | 输出全部的参数和系统属性 | 
| -flag name | 输出对应名称的参数 | 
| -flag [±]name | 开启或者关闭对应名称的参数 只有被标记为manageable的参数才可以被动态修改 | 
| -flag name=value | 设定对应名称的参数 | 
| -flags | 输出全部的参数 | 
| -sysprops | 输出系统属性 | 
【1】查看
-  
jinfo -sysprops 进程id
-  
可以查看由System.getProperties()取得的参数
 -  
13152代表进程id

 
 -  
 -  
jinfo -flags 进程id
- 查看曾经赋过值的一些参数
 
 -  
jinfo -flag 参数名称 进程id
-  
查看某个java进程的具体参数信息

 
 -  
 
【2】修改
-  
针对boolean类型
-  
jinfo -flag [+|-]参数名称 进程id

 
 -  
 -  
针对非boolean类型
-  
jinfo -flag 参数名称=参数值 进程id

 
 -  
 
3、拓展
-  
java -XX:+PrintFlagsInitial
- 查看所有JVM参数启动的初始值
 
 -  
java -XX:+PrintFlagsFinal
-  
查看所有JVM参数的最终值
 -  
值前面添加**冒号:**的是修改之后的值,没有添加的都是没有发生改变的初始值

 
 -  
 -  
java -参数名称:+PrintCommandLineFlags
- 查看那些已经被用户或者JVM设置过的详细的XX参数的名称和值
 
 
第5章、jmap:导出内存映像文件&内存使用情况
1、基本情况
- jmap(JVM Memory Map):作用一方面是获取dump文件(堆转储快照文件,二进制文件),它还可以获取目标Java进程的内存相关信息,包括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等
 - 开发人员可以在控制台中输入命令“jmap -help”查阅jmap工具的具体使用方式和一些标准选项配置
 - 官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jmap.html
 
2、基本语法
-  
基本语法:
-  
jmap [option]
 -  
jmap [option] <executable
 -  
jmap [option] [server_id@]
 
 -  
 -  
option包括:
 
| 选项 | 作用 | 
|---|---|
| -dump | 生成dump文件(Java堆转储快照),-dump:live只保存堆中的存活对象 | 
| -heap | 输出整个堆空间的详细信息,包括GC的使用、堆配置信息,以及内存的使用信息等 | 
| -histo | 输出堆空间中对象的统计信息,包括类、实例数量和合计容量,-histo:live只统计堆中的存活对象 | 
| -J | 传递参数给jmap启动的jvm | 
| -finalizerinfo | 显示在F-Queue中等待Finalizer线程执行finalize方法的对象,仅linux/solaris平台有效 | 
| -permstat | 以ClassLoader为统计口径输出永久代的内存状态信息,仅linux/solaris平台有效 | 
| -F | 当虚拟机进程对-dump选项没有任何响应时,强制执行生成dump文件,仅linux/solaris平台有效 | 
- 注:这些参数和linux下输入显示的命令多少会有不同,包括也受jdk版本的影响
 - 1、使用语法可以通过在DOS窗口中使用jmap/jmap -h/jmap -help查看
 - 2、<executable 代表可执行的代码,比如使用> 文件名称来指定生成的dump文件的生成位置
 - 3、[server_id@]<……>是为远程连接准备的
 
3、使用:导出内存映像文件
- 一般来说,使用jmap指令生成dump文件的操作算得上是最常用的jmap命令之一,将堆中所有存活对象导出至一个文件之中
 - Heap Dump又叫做堆存储文件,指一个Java进程在某个时间点的内存快照
 - Heap Dump在触发内存快照的时候会保存此刻的信息如下: 
  
- All Objects 
    
- Class,fields,primitive values and references
 
 - All Classes
 - ClassLoader,name,super class,static fields
 - Garbage collectio Roots 
    
- objects defined to be reachable by the JVM
 
 - Thread Stacks and Local Variables 
    
- The call-stacks of threads at the moment of the snapshot,and per-frameinformation about local objects
 
 
 - All Objects 
    
 - 说明: 
  
- 1:通常在写Heap Dump文件前会触发一次Full GC,所以heap dump文件里保存的都是Fu11GC后留下的对象信息
 - 2:由于生成dump文件比较耗时,因此大家需要耐心等待,尤其是大内存镜像生成dump文件则需要耗费更长的时间来完成
 
 - 注意: 
  
- 1、对于以上说明中的第1点是自动方式才会这样做,而手动不会在Full GC之后生成Dump
 - 2、使用手动方式生成dump文件,一般指令执行之后就会生成,不用等到快出现OOM的时候
 - 3、使用自动方式生成dump文件,当出现OOM之前先生成dump文件
 - 4、如果使用手动方式,一般使用第2种,毕竟生成堆中存活对象的dump文件是比较小的,便于传输和分析
 
 - 什么时候用自动,什么时候用手动? 
  
- 当程序出现OOM的时候,需要监控这一刻的情况,就需要使用自动的方式,程序执行中则使用手动方式
 
 
【1】手动的方式
- jmap -dump:format=b,file=<filename.hprof> 
  
- 所有的
 
 - jmap -dump:live,format=b,file=<filename.hprof> 
  
- 只导出存活的
 
 
【2】自动的方式
-  
自动的两种方式:
-  
-XX:+HeapDumpOnOutOfMemoryError
 -  
-XX:HeapDumpPath=<filename.hprof>
 
 -  
 -  
当程序发生OOM退出系统时,一些瞬时信息都随着程序的终止而消失,而重现OOM问题往往比较困难或者耗时。此时若能在OOM时,自动导出dump文件就显得非常迫切。
 -  
这里介绍一种比较常用的取得堆快照文件的方法,即使用:
- -XX:+HeapDumpOnoutOfMemoryError:在程序发生oOM时,导出应用程序的当前堆快照
 - -XX :HeapDumpPath:可以指定堆快照的保存位置。
 - 例如:-Xmx100m -XX:+HeapDumpOnoutOfMemoryError -XX:HeapDumpPath=D: \m.hprof
 
 

4、使用:显示堆内存相关信息
- jmap -heap 进程id 
  
- jmap -heap 进程id:只是时间点上的堆信息
 - jstat后面可以添加参数,可以指定时间动态观察数据改变情况
 - 图形化界面工具,例如jvisualvm等,它们可以用图表的方式动态展示出相关信息
 - 总结:jmap 不如 jstat 不如 图形化界面工具
 
 - jmap -histo 进程id 
  
- 输出堆中对象的同级信息,包括类、实例数量和合计容量,也是这一时刻的内存中的对象信息
 
 
5、使用:其他作用
- 这两个指令仅linux/solaris平台有效,所以无法在windows操作平台上演示,并且使用比较小众
 - jmap -permstat 进程id 
  
- 查看系统的ClassLoader信息
 
 - jmap -finalizerinfo 
  
- 查看堆积在finalizer队列中的对象
 
 
6、小结
- 由于jmap将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap需要借助安全点机制,让所有线程停留在不改变堆中数据的状态。也就是说,由jmap导出的堆快照必定是安全点位置的。这可能导致基于该堆快照的分析结果存在偏差
 - 例如,假设在编译生成的机器码中,某些对象的生命周期在两个安全点之间,那么:live选项将无法探知到这些对象。
 - 另外,如果某个线程长时间无法跑到安全点,jmap将一直等下去
 - 对于jstat,垃圾回收器会主动将jstat所需要的摘要数据保存至固定位置之中,而jstat只需直接读取即可。
 
第6章、jhat:JDK自带堆分析工具
- jhat命令在jdk9及其之后就被移除了,官方建议使用jvisualVM代替jhat,只需了解
 
1、基本情况
- jhat(JVM Heap Analysis Tool) :
 - Sun JDK提供的jhat命令与jmap命令搭配使用,用于分析jmap生成的heap dump文件(堆转储快照)
 - jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,用户可以在浏览器中查看分析结果(分析虚拟机转储快照信息)
 - 使用了jhat命令,就启动了一个http服务,端口是7000,即http://localhost:7000/,就可以在浏览器里分析
 
2、基本语法
- 基本语法:jhat [option] [dumpfile] 
  
- dumpfile代表dump文件的地址以及名称
 
 - option 参数
 
| 参数 | 说明 | 
|---|---|
| -stack false | true | 关闭 / 打开对象分配调用栈跟踪 | 
| -refs false | true | 关闭 / 打开对象引用跟踪 | 
| -port port-number | 设置jhat HTTP,Server的端口号,默认7000 | 
| -exclude exclude-file | 执行对象查询时需要排除的数据成员 | 
| -baseline exclude-file | 指定一个基准堆转储 | 
| -debug int | 设置debug级别 | 
| -version | 启动后显示版本信息就退出 | 
第7章、jstack:打印JVM中线程快照
1、基本情况
- jstack(JVM Stack Trace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合
 - 生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用jstack显示各个线程调用的堆栈情况
 - 官方文档:https://docs.oracle.com/en/java/javase/11/tools/jstack.html
 - 在thread dump中,要留意下面几种状态: 
  
- 死锁,Deadlock(重点)
 - 等待资源,waiting on condition(重点)
 - 等待获取监视器,waiting on monitor entry(重点)
 - 阻塞,Blocked(重点)
 - 执行中,Runnable
 - 暂停,Suspended
 - 对象等待中,object.wait() 或 TIMED_WAITING
 - 停止,Parked
 
 
2、基本语法
-  
基本语法:jstack [option] [pid]
C:\Users\AlphonseKino>jstack Usage: jstack [-l] <pid> (to connect to running process) jstack -F [-m] [-l] <pid> (to connect to a hung process) jstack [-m] [-l] <executable> <core> (to connect to a core file) jstack [-m] [-l] [server_id@]<remote server IP or hostname> (to connect to a remote debug server) Options: -F to force a thread dump. Use when jstack <pid> does not respond (process is hung) -m to print both java and native frames (mixed mode) -l long listing. Prints additional information about locks -h or -help to print this help message -  
option参数
 
| 参数 | 说明 | 
|---|---|
| -F | 当正常输出的请求不被响应时,强制输出线程堆栈 | 
| -l | 除堆栈外,显示关于锁的附加信息 | 
| -m | 如果调用本地方法的话,可以显示C/C++的堆栈 | 
| -h | 帮助操作 | 
-  
jstack管理远程进程的话,需要在远程程序的启动参数中增加:
-Djava.rmi.server.hostname=···.. -Dcom.sun.management .jmxremote -Dcom.sun.management .jmxremote.port=8888 -Dcom.sun.management .jmxremote.authenticate=false -Dcom. sun.management .jmxremote.ssl=false -  
如果程序出现等待问题,可以使用该指令去查看问题所在,结果中也会提示你问题所在
 
第8章、jcmd:多功能命令行
1、基本情况
- 在JDK 1.7以后,新增了一个命令行工具jcmd
 - 它是一个多功能的工具,可以用来实现前面除了jstat之外所有命令的功能。比如:用它来导出堆、内存使用、查看Java进程、导出线程信息、执行GC、JVM运行时间等
 - 官方帮助文档:https : //docs.oracle.com/en/java/javase/11/tools/jcmd. html
 - jcmd拥有jmap的大部分功能,并且在Oracle的官方网站上也推荐使用jcmd命令代jmap命令
 
2、基本语法
| 语句 | 说明 | 
|---|---|
| jcmd -l | 列出所有的JVM进程 | 
| jcmd 进程号 help | 针对指定的进程,列出支持的所有具体命令 | 
| jcmd 进程号 具体命令 | 显示指定进程的指令命令的数据 | 
- 根据以上命令来替换之前的那些操作: 
  
- Thread.print 可以替换 jstack指令
 - GC.class_histogram 可以替换 jmap中的-histo操作
 - GC.heap_dump 可以替换 jmap中的-dump操作
 - GC.run 可以查看GC的执行情况
 - VM.uptime 可以查看程序的总执行时间,可以替换jstat指令中的-t操作
 - VM.system_properties 可以替换 jinfo -sysprops 进程id
 - VM.flags 可以获取JVM的配置参数信息
 
 

第9章、jstatd:远程主机信息收集
- 之前的指令只涉及到监控本机的Java应用程序,而在这些工具中,一些监控工具也支持对远程计算机的监控(如jps、jstat)。为了启用远程监控,则需要配合使用jstatd 工具
 - 命令jstatd是一个RMI服务端程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信。jstatd服务器将本机的Java应用程序信息传递到远程计算机
 










