JVM 性能监控与调优
相关概念
性能监控
一种以非强行或者入侵方式收集或查看应用运营性能数据的活动。
监控通常是指一种在生产、质量评估或者开发环境下实施的带有预防或主动性的活动。
当应用相关干系人提出性能问题却没有提供足够多的线索时,首先我们需要进行性能监控,随后是性能分析。
- GC 频繁
- CPU load 过高
- OOM
- 内存泄漏
- 死锁
- 程序响应时间较长
性能分析
一种以侵入方式收集运行性能数据的活动,它会影响应用的吞吐量或响应性。
性能分析是针对性能问题的答复结果,关注的范围通常比性能监控更加集中。
性能分析很少在生产环境下进行,通常是在质量评估、系统测试或者开发环境下进行,是性能监控之后的步骤。
- 打印 GC 日志,通过 GCview 或者 GCEasy 来分析日志信息
- 灵活运用,命令行工具,jstack、jmap、jinfo等
- dump 出堆文件,使用内存分析工具分析文件
- 使用阿里 Arthas,或 jconsole、JVisualVM 来实时查看 JVM 状态
- jstack 查看堆栈信息
性能调优
一种为改善应用响应性或吞吐量而更改参数、源代码、属性配置的活动,性能调优是在性能监控、性能分析之后的活动。目的是以较小的内存占用,获得较高的吞吐量或改善响应时间,减少 GC 的频率和 Full GC 的次数。
适当增加内存,根据业务背景选择垃圾回收器
优化代码,控制内存使用
增加机器,分散节点压力
合理设置线程池线程数量
使用中间件提高程序效率,比如缓存,消息队列等
…
命令行工具
jps
jps(Java Process Status):显示指定系统内所有的 HotSpot 虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程。
对本地虚拟机进程来说,进程的本地虚拟机 ID 与操作系统的进程ID 是一致的,是唯一的。
jps [-q] [-mlvV] [
-q:仅仅显示本地虚拟机唯一 ID。不显示主类的名称
-l:输出应用程序主类的全类名,如果进程执行的是 jar 包,则输出 jar 包的完整路径
-m:输出虚拟机进程启动时传递给主类 main() 的参数
-v:列出虚拟机进程启动时的 JVM 参数
使用参数 -XX:-UsePerfData
, 那么 jps 及 jstat 将无法从一个叫 PerfData 的共享文件获取数据,即探知不到该进程的信息
jstat
jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
jstat -
- -class:显示 ClassLoader 的相关信息:类的装载数量、卸载数量及占用空间类、装载所消耗的时间等
- -t:程序持续时间
:指定毫秒重复执行 :执行次数 - -h:设置每隔指定条输出信息后打印表头
eg:每隔一秒打印一次类加载信息和程序执行时间,执行 10 次后终止
1 | C:\Users\user>jps |
JIT 相关:
- -compiler:显示 JIT 编译器编译过的方法、耗时等信息
- -printcompilation:输出已经被 JIT 编译的方法
GC 相关:
- -gc:显示与 GC 相关的堆信息。包括 Eden 区、两个 Survivor区、老年代永久代等的容量、早用空间、GC时间合计等信息
- -gcutil:与 -gc 基本相同,但输出的为已使用空间占总空间的百分比
- -gccause:与 -gcutil 功能一样,但是会额外输出导致最后一次或当前正在发生的 GC 产生的原因
- -capacity:与 -gc 基本相同,但输出主要关注 Java 堆各个区域使用到的最大、最小空间
- -gcnew:新生代 GC 状况
- -gcnewcapacity:与 -gcnew 基本相同,输出主要关注使用到的最大、最小空间
- -gold:老年代 GC 状况
jinfo
jinfo(Configuralion Info for Java):实时查看和修改 JVM 配置参数
jinfo [option]
- no option:输出全部的参数和系统属性
- -flag name:输出对应名称的参数
- -flags:查看全部的参数
- -sysprops:查看系统属性
1 | C:\Users\user>jinfo -flags 3740 |
- -flag [±]name:开启或者关闭对应名称的参数。只有被标记为 manageable 的参数才可以被动态修改
- -flag name=value:设定对应名称的参数
并非所有参数都支持动态修改。参数只有被标记为 manageable 的 flag 可以被实时修改。其实,这个修改能力是极其有限的。
1 | C:\Users\user>java -XX:+PrintFlagsFinal -version | findstr manageable |
java -XX+PrintFlagslnitial PID
:查看所有 JVM 参数启动的初始值。
java -XX:+PrintFlagsFinal PID
:查看所有 JVM 参数的最终值。
java -XX+PrintCommandLineFlags PID
:查看已经被用户或者 JVM 设置过的详细参数名称和值。
jmap
jmap(JVM Memory Map):导出内存映像文件/内存使用情况
jmap [option] (to connect to running process)
jmap [option] <executable (to connect to a core file)
- -dump:生成 dump 文件,-dump:live 只保存堆中存活的对象
- -heap:输出整个堆空间的详细信息,包括 GC 的使用、堆配置信息,以及内存的使用信息等
- -histo:输出堆空间中对象的统计信息,包括类、实例数量和合计容量
- -permstat:以 ClassLoader 为统计口径输出永久代的内存状态信息(仅 linux/solaris 平台有效)
- -finalizerinfo:显示在 F-Queue 中等待 Finalizer 线程执行 finalize 方法的对象(仅 linux/solaris 平台有效)
- -F:当虚拟机进程对-dump 选项没有任何响应时,强制执行生成 dump 文件(仅 linux/solaris 平台有效)
由 jmap 导出的堆快照必定是安全点位置的。这可能导致基于该堆快照的分析结果存在偏差。如果某个线程长时间无法跑到安全点, jmap 将一直等下去。
手动生成 dump 文件:
jmap -dump:format=b,file=<filename.hprof>
jmap -dump:live,format=b,file=<filename.hprof> // 存活对象
通过 VM 参数自动生成 dump 文件:
-XX:+HeapDumpOnOutOfMemoryError:在程序发生 OOM 时,导出应用程序的当前堆快照
-XX:HeapDumpPath=<filename.hprof>:可以指定堆快照的保存位置
查看各区大小:
jmap -heap pid
所有类型使用的内存:
jmap -histo pid
jhat
jhat(JVM Heap Analysis Tool):分析 dump 文件。
在 7000 端口启动一个 http 服务器,在 JDK9、JDK10 中已经被删除,官方建议用 VisualVM 代替
jstack
jstack(JVM stlack Trace):查看所有线程信息
jstack [option]
- -F:当正常输出的请求不被响应时,强制输出线程堆栈
- -I:额外显示关于锁的附加信息
- -m:如果调用到本地方法,可以显示 C/C++的堆栈
- -h:帮助操作
jcmd
多功能命令行,可以用来实现前面除了 jstat 之外所有命令的功能。比如:用它来导出堆、内存使用、查看 Java 进程、导出线程信息、执行 GC、JVM 运行时间等。
jcmd -l
:列出所有的 JVM 进程
jcmd pid help
:针对指定的进程,列出支持的所有命令
jcmd pid 具体命令
:显示指定进程的指令命令数据。
1 | C:\Users\user>jcmd 20660 help |
GUI 工具
JConsole
能够检查堆中各部分内存和非堆内存的使用情况、线程信息、死锁、类的加载数量、VM 概要信息等。
Visual VM
本地连接:
监控本地 Java 进程的 CPU、类、线程等
远程连接:
- 确定远程服务器的 IP 地址
- 添加 JMX(通过 JMX 技术具体监控远程服务器哪个 Java 进程)
- 修改 bin/catalina.sh 文件,连接远程的 tomcat
- 在 …/conf 中添加 jmxremote.access 和 jmxremote.password 文件
- 将服务器地址改成公网 IP 地址
- 设置阿里云安全策略和防火墙策略
- 启动 tomcat,查看 tomcat 启动日志和端口监听
- JMX 中输入端口号、用户名、密码登录