一、性能监控与调优
1.1 命令行
1.1.1 jps查看正在运行的Java进程
- 显示指定系统内所有的HotSpot虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程。
- 说明:对于本地虚拟机进程来说,进程的本地虚拟机ID与操作系统的进程ID是一致的,是唯一的。
- 基本语法
- jsp [options] [hostid]
- -q :仅仅显示LVMID(local virtual machine id), 即本地虚拟机唯一id。不显示主类的名称等
- -l :输出应用程序主类的全类名或如果进程执行的是jar包, 则输出jar完整路径
- -m :输出虚拟机进程启动时传递给主类main()的参数
- -v :列出虚拟机进程启动时的JVM参数。比如: -Xms20m -Xmx50m是 启动程序指定的jvm参数
- (以上参数可以综合使用)
- 如果某Java进程关闭了默认开启的UsePerfData参数(即使用参数-XX: -UsePerfData) ,那么jps命令(以及下面介绍的jstat)将无法探知该Java进程。
- jsp [options] [hostid]
1.1.2 jstat查看JVM统计信息
-
jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
-
在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。常用于检测垃圾回收问题以及内存泄漏问题。
- 官方文档:https://docs.oracle.com/javase/8/docs/technotes/too1s/unix/jstat.html
-
基本语法
- jstat - [-t] [-h] [ []]
- option参数
- 类装载相关:
- -class: 显示ClassLoader的相关信息: 类的装载、卸载数量、总空间、类装载所消耗的时间等
- 垃圾回收相关
- -gc: 显示与GC相关的堆信息。包括Eden区、两个Survivor区、老年代、永久代等的容量、己用空间、GC时间合计等信息。
- -gccapacity:显示内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
- -gcutil:显示内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比。
- -gccause:与-gcuti1功能一 样,但是会额外输出导致最后一次或当前正在发生的GC产生的原因。
- -gcnew:显示新生代GC状况
- -gcnewcapacity:显示内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
- -geold:显示老年代GC状况
- JIT相关
- -compiler:显示JIT编译器编译过的方法、耗时等信息
- -printcompilation:输出已经被JIT编译的方法
- interval参数: 用于指定输出统计数据的周期,单位为毫秒。即:查询间隔
- 如: jstat -class 9000 1000 (打印进程为9000的,每1s打印一次)
- count参数: 用于指定查询总次数
- 如: jstat -class 9000 1000 10 (打印进程为9000的,每1s打印一次,总共打印10次)
- -t 参数: 可以在输出信息前加上一个Timestamp列,显示程序的运行时间。单位:秒
- -h 参数: 可以在周期性数据输出时,输出多少行数据后输出一个表头信息
- 如: jstat -class -h3 9000 1000 10 (每三条数据就重新打印表头)
1.1.3 jinfo实时查看和修改JVM配置参数
- jinfo(Configuration Info for Java)查看虚拟机配置参数信息,也可用于调整虛拟机的配置参数。
- 在很多情况下,Java应用程序不会指定所有的Java虚拟机参数。而此时,开发人员可能不知道某一个具体的Java虚拟机参数的默认值。在这种情况下,可能需要通过查找文档获取某个参数的默认值。这个查找过程可能是非常艰难的。但有了jinfo工具,开发人员可以很方便地找到Java虚拟机参数的当前值。
- 基本语法
- jinfo [option] PID
- jinfo -sysprops PID: 可以查看由System.getProperties()取得的参数
- jinfo -flags PID: 查看曾经赋过值的一些参数
- jinfo -flags 具体参数 PID:查看某个java进程的具体参数的值
- jinfo -flag [+/-]具体参数 PID: 动态修改参数
- jinfo -flag 具体参数=具体值 PID: 动态修改参数
- 拓展
- java -XX:+PrintFlagsInitial 查看所有JVM参数启动的初始值
- java -XX:+PrintFlagsFinal 查看所有JVM参数的最终值
- java -XX:+PrintCommandLineFlags 查看已经被用户或者JVM设置过的详细的XX参数的名称和值
- jinfo [option] PID
1.1.4 jmap导出内存映像文件&内存使用情况
-
jmap (JVM Memory Map): 作用一方面是获取dump文件(堆转储快照文件,二进制文件),它还可以获取目标Java进程的内存相关信息,包括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等。
-
开发人员可以在控制台中输入命令“jmap -help”查阅jmap工具的具体使用方式和一些标准选项配置。
-
官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jmap.html
-
基本语法:
-
-dump:
- 生成Java堆转储快照: dump文件
- 特别的: -dump:live只保存堆中的存活对象
-
-heap:输出整个堆空间的详细信息,包括GC的使用、堆配置信息,以及内存的使用信息等
-
-histo:
- 输出堆中对象的统计信息,包括类、实例数量和合计容量
- 特别的,-histo:live只统计堆中的存活对象
-
-permstat:
- 以ClassLoader为统计口径输出永久代的内存状态信息
- 仅linux/solaris平台有效
-
-finalizeinfo
- 显示在F-Queue中等待Finalizer线程执行finalize方法的对象
- 仅linux/solaris平台有效
-
-f
- 当虚拟机进程对-dump选项没有任何响应时,可使用此选项强制执行生成dump文件
- 仅linux/solaris平台有效
-
-h / -help: -jmap工具使用的帮助命令
-
-f :传递参数给jmap启动的jvm
-
-
使用:
- 导出内存映像文件
- 手动:
- jmap -dump:format=b,file=<filename.hprof>
- jmap -dump:live,format=b,file=<filename.hprof>
- 自动
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:HeapDumpPath=<filename.hprof>
- 手动:
- 显示堆内存相关信息
- jmap -heap pid
- jmap -histo pid
- jmap -permstat pid 查看系统的ClassLoader信息
- jmap -finalizerinfo 查看堆积在finalizer队列中的对象
- 导出内存映像文件
1.1.5 jhat在JDK中自带堆分析工具
- jhat(JVM Heap Analysis Tool)
- Sun JDK提供的jhat命令与jmap命令搭配使用,用于分析jmap生成的heap dump文件(堆转储快照)。jhat内置了一个微型的HTTP/HTML服务器, 生成dump文件的分析结果后, 用户可以在浏览器中查看分析结果(分析虚拟机转储快照信息)。
- 使用了jhat命令,就启动了一个http服务,端口是7000,即http://localhost:7000/就可以在浏览器里分析
- 说明: jhat命令在JDK9、JDK10中 已经被删除,官方建议用VisualVM代替。
- 基本语法
- jhat [option] [dumpfile]
- option参数
- -stack false/ture: 关闭/打开对象分配调用栈跟踪
- -refs false/ture: 关闭/打开引用跟踪
- -port port-number:设置jhat HTTP Server的端口号,默认7000
- -exclude exclude-file: 执行对象查询时需要排除的数据成员
- -baseline exclude-file: 指定一个基准转储
- -dubug int: 设置debug级别
- -version: 启动后显示版本信息就退出
- -J :传入启动参数,比如-J -Xmx512m
1.1.6 jstack打印JVM中线程快照
-
jstack(JVMStackTrace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。线程快照 就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。
-
生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用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
-
基本语法
- jstack [option]
- option参数
- -F 当正常输出的请求不被响应时,强制输出线程堆栈
- -l 除堆栈外,显示关于锁的附加信息
- -m 如果调用到本地方法的话,可以显示C/C++的堆栈
- -h 帮助操作
1.1.7 jcmd多功能命令行
- 在JDK 1.7以后,新增了一个命令行工具jcmd。
- 它是一个多功能的工具,可以用来实现前面除了jstat之外所有命令的功能。比如:用它来导出堆、内存使用、查看Java进程、导出线程信息、执行GC、JVM运行时间等。
- 官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jcmd.html
- jcmd拥有jmap的大部分功能,并且在Oracle的官方网站上也推荐使用jcmd命令代jmap命令
- 基本语法
- jcmd -l 列出所有的JVM进程
- jcmd pid help 针对指定的进程,列出支持的所有命令
- jcmd pid 具体命令: 显示指定进程的指令命令的数据
1.1.8 jstatd远程主机信息收集
- 之前的指令只涉及到监控本机的Java应用程序,而在这些工具中,一些监控工具也支持对远程计算机的监控(如jps、jstat)。为了启用远程监控,则需要配合使用jstatd工具。
- 命令jstatd是一个RMI服务端程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信。
jstatd服务器将本机的Java应用程序信息传递到远程计算机。