判断是否需要调优
如果各项参数设置合理,系统没有超时日志或异常信息的出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化,如果GC时间超过1~3s,或者频繁GC,则必须优化,遇到下面的情况,就需要考虑进行jvm调优:
- 系统吞吐量与相应性能不高或下降
- Heap内存(老年代)持续上涨达到设置的最大内存值
- FullGC次数频繁
- GC停顿时间过长
- 应用出现OutOfMemory等内存异常
- 应用中有使用本地缓存且占用大量内存空间
调优目标
调优的最终目的是为了应用程序使用最小的硬件来承载更大的吞吐量或低延时,jvm调优主要针对垃圾收集器的收集性能优化,减少gc的频率和full gc的次数,使运行在虚拟机上的应用能使用更少的内存,提高吞吐量,降低延迟
下面举一些目标例子:
- 堆内存使用率<=70%
- 老年代内存使用率<=70%
- avgpause<=1s
- full gc 次数为0或平均暂停间隔时间>=24h
调优顺序
程序所需内存->时间延迟->吞吐量
调优工具
1. jps
JVM Process Status Tool,可以查看java进程
1.1 语法
jps:列出Java程序进程ID和Main函数名称
jps -q:只输出进程ID
jps -m:输出传递给Java进程(主函数)的参数
jps -l:输出主函数的完整路径
jps -v:显示传递给Java虚拟的参数
2. jstat
JVM Statistics Monitoring Tool jstat 可以查看java程序运行时相关信息
2.1 语法
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
option可通过
jstat -options
获取
options可选值
-class:显示ClassLoader的相关信息
-compiler:显示JIT编译的相关信息
-gc:显示与GC相关信息
-gccapacity:显示各个代的容量和使用情况
-gccause:显示垃圾收集相关信息(同-gcutil),同时显示最后一次或当前正在发生的垃圾收集的诱发原因
-gcnew:显示新生代信息
-gcnewcapacity:显示新生代大小和使用情况
-gcold:显示老年代信息
-gcoldcapacity:显示老年代大小
-gcpermcapacity:显示永久代大小
-gcutil:显示垃圾收集信息
-printcompilation:输出JIT编译的方法信息
-t:在输出信息前加上一个Timestamp列,显示程序的运行时间
-h:可以在周期性数据输出后,输出多少行数据后,跟着一个表头信息
interval:用于指定输出统计数据的周期,单位为毫秒
count:用于指定一个输出多少次数据
2.2 示例
查询进程ID为4145的java程序的GC信息,采样时间1000ms,采样数量为2
jstat -gc 4145 1000 2
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
125440.0 127488.0 0.0 2192.1 768512.0 294475.5 494080.0 185113.9 96216.0 91689.8 11520.0 10547.7 23 3.431 4 2.970 6.401
125440.0 127488.0 0.0 2192.1 768512.0 294475.5 494080.0 185113.9 96216.0 91689.8 11520.0 10547.7 23 3.431 4 2.970 6.401
2.3 注解
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC :年轻代中Eden(伊甸园)的容量 (字节)
EU :年轻代中Eden(伊甸园)前已使空间 (字节)
OC :Old代的容量 (字节)
OU :Old代目前已使用空间 (字节)
MC:metaspace(元空间)的容量 (字节)
MU:metaspace(元空间)目前已使用空间 (字节)
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC :从应用程序启动到采样时年轻代中gc次数
YGCT :从应用程序启动到采样时年轻代中gc所用时间(s)
FGC :从应用程序启动到采样时old代(全gc)gc次数
FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
3 jinfo
Java Configuration Info 可以用来查看正在运行的java程序的扩展参数,支持运行时修改部分参数
jinfo [option] <pid>
jinfo [option] <executable <core>
3.1 示例1:查询进行ID4145的最大堆值
flag name 可通过
jinfo -flags pid
打印
jinfo -flag MaxHeapSize 4145
3.2 查询4145的所有参数
jinfo -flags 4145
4. jmap
Memory Map 可以查看堆内存的使用情况,一般集合jhat使用
4.1 用法
jmap [option] <pid>
option可选值
no option: 查看进程的内存映像信息,类似 Solaris pmap 命令
heap: 显示Java堆详细信息
histo[:live]: 显示堆中对象的统计信息
clstats:打印类加载器信息
finalizerinfo: 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
dump:<dump-options>:生成堆转储快照 F:当-dump没有响应时,使用-dump或者-histo参数。在这个模式下,live子参数无效
help:打印帮助信息 J<flag>:指定传递给运行jmap的JVM的参数
4.2 示例
打印java堆的详细信息
jmap -heap 4145
生成堆快照dump文件,线上慎用,会暂停应用
jmap -dump:format=b,file=heapdump.dump pid
5 jhat
Java Heap Analysis Tool, 解析Java堆转储文件并启动一个 web server,然后用浏览器来查看、浏览 dump 出来的 heap
5.1 语法
jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file>
5.2 示例开启一个本地服务解析dump文件
jhat dump-flie-path
6 jstack
jstack命令通常配置top使用,通过top -H -p pid定位java进程和线程,再利用jstack -l pid 导出线程栈,一般需要多次dump,每次隔5s
6.1 语法
jstack [-l] <pid> 查看当前时间点,指定进程的dump堆栈信息
jstack -F [-m] [-l] <pid>
jstack [-m] [-l] <executable> <core>
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
option可选值
-F 强制jstack。当进程挂起了,此时'jstack [-l] pid'是没有响应的,这时候可使用此参数来强制打印堆栈信息,一般情况不需要使用。
-m 打印java和native c/c++框架的所有栈信息。可以打印JVM的堆栈,以及Native的栈帧,一般应用排查不需要使用。
-l 长列表。打印关于锁的附加信息。例如属于java.util.concurrent的ownable synchronizers列表,会使得JVM停顿得久得多(可能会差很多倍,如普通的jstack可能毫秒和次GC没区别,加了-l 就是近一秒的时间),-l 建议不要用。一般情况不需要使用。-h or -hel 打印帮助信息
7 hprof
Heap/CPU Profiling Tool 能够展现CPU使用率,统计堆内存使用情况
7.1 语法
java -agentlib:hprof[=options] ToBeProfiledClassjava -Xrunprof[:options] ToBeProfiledClassjavac -J-agentlib:hprof[=options] ToBeProfiledClass
8 jconsole
Java Monitoring and Management Console,Java 5引入,一个内置 Java 性能分析器,可以从命令行或在 GUI shell 中运行。您可以轻松地使用 JConsole来监控 Java 应用程序性能和跟踪Java 中的代码
性能诊断工具
针对java应用,诊断工具主要分为两层:OS层面和java应用层面(包括代码诊断和GC诊断)
OS诊断
针对os我们需要关注:CPU、Memory、I/O
CPU
cpu需要关注平均负载(Load Average), CPU使用率,上下文切换次数(Context Switch)
- 通过top命令可以查看系统平均负载和cpu使用率
Load Avg的三个数字分别表示过去1分钟、5分钟、15分钟的机器负载,若数值小于0.7*cpu个数,则系统工作正常,若超过这个值,甚至达到cpu核数的四五倍,则系统的负载明显偏高 - 通过vmstat命令可以查看cpu的上下文切换次数
Memory
使用free -m命令查看内存使用情况
通过top命令查看进程使用的虚拟内存virt和物理内存res,根据公式virt=swap+res可以推算出具体应用使用的交换分区,使用交换分区过大会影响java的性能
I/O
I/O包括磁盘I/O和网络I/O,一般情况下磁盘更容易出现I/O瓶颈,通过iostat可以查看磁盘的读写情况,通过cpu的I/O wait查看磁盘I/O是否正常