性能问题排查

JVM日常工具、命令

Linux解压/打包jar

解压

1
2
jar  -xvf  xx.jar 
jar -cvfM0 xx.jar ./

打包

1
2
unzip XXX.jar -d app
jar cvfm0 MR-XDR-JMR-NEW.jar META-INF/MANIFEST.MF

Java远程debug

1
java -Xdebug -Xrunjdwp:transport=dt_socket, server=y, suspend=n, address=8787 -jar xx.jar

线程定位

1
2
3
4
5
6
7
top 获取当前CPU使用率
top -Hp pid 获取当前进程中各个线程资源使用情况
jstack pid 获取当前进程中线程堆栈
printf '%x\n' pid 将资源使用率较高的线程pid转为16进制,并且在线程堆栈中通过nid找到对应线程
jstack 1149 | grep 45a2
jstack pid >stack.dump
查看线程状态 RUNNABLE / WAITING / BLOCKED

JVM内存查看

系统内存相关

1
2
cat /proc/meminfo 查看系统内存
free -m 获取内存使用情况 (-K, -M ,-G)

total:总计物理内存的大小, used:已使用多大, free:可用有多少, Shared:多个进程共享的内存总额, Buffers/cached:磁盘缓存的大小。

JVM内存相关

jinfo pid / jinfo -flags pid 查看指定pid的所有JVM信息
jmap -heap pid 查看堆内存使用情况

1
2
3
4
5
Xms/InitialHeapSize | 堆内存大小的初始值
Xmx/MaxHeapSize | 堆内存大小的上限
Xmn/MaxnewSize | 新生代可被分配的内存的最大上限
XX:NewRatio | Yong和Old的比例|默认为2
XX:SurvivorRatio | Survivor:Eden|默认为8

Jstat

jstat -gcutil pid / jstat -gc pid

1
2
3
4
5
6
7
8
9
10
11
S0: Survivor 0区的空间使用率 Survivor space 0 utilization as a percentage of the space's current capacity. 
S1: Survivor 1区的空间使用率 Survivor space 1 utilization as a percentage of the space's current capacity.
E: Eden区的空间使用率 Eden space utilization as a percentage of the space's current capacity.
O: 老年代的空间使用率 Old space utilization as a percentage of the space's current capacity.
M: 元数据的空间使用率 Metaspace utilization as a percentage of the space's current capacity.
CCS: 类指针压缩空间使用率 Compressed class space utilization as a percentage.
YGC: 新生代GC次数 Number of young generation GC events.
YGCT: 新生代GC总时长 Young generation garbage collection time.
FGC: Full GC次数 Number of full GC events.
FGCT: Full GC总时长 Full garbage collection time.
GCT: 总共的GC时长 Total garbage collection time.

JVM启动配置

1
-Xms512m -Xmx2024m -Xmn256m -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseParallelGC -XX:TargetSurvivorRatio=90 -XX:SurvivorRatio=8 -Djava.awt.headless=true

-XX:SurvivorRatio=8显式指定Eden和Survivor的比列,因为在jdk8中,默认使用UseParallelGC策略,这种策略下会打开AdaptiveSizePolicy参数,这个参数的意思是的每次GC后会重新计算Eden、From和To区的大小,计算依据是GC过程中统计的GC时间、吞吐量、内存占用量,所以Eden和Survivor的比列会变化,所以我们要显式的指定大小,从而关闭动态调整的策略.其他关闭AdaptiveSizePolicy的方式有指定CMS回收器,在CMS中,AdaptiveSizePolicy是默认关闭的

java gc log

1
2
3
4
5
6
7
-XX:+PrintGC 输出GC日志
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-Xloggc:../logs/gc.log 日志文件的输出路径
 -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gclogs

dump

获取当前dump文件 jmap -dump:format=b,file=serviceDump.dat 104390

火焰图

1
2
3
4
5
6
下载perf
采样 perf record -p 126023 -F 999 -a -g -- sleep 60
perf script -i perf.data &> perf.unfold
git clone https://github.com/brendangregg/FlameGraph.git
./FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
./FlameGraph/flamegraph.pl perf.folded > perf.svg

y 轴表示调用栈, 每一层都是一个函数. 调用栈越深, 火焰就越高, 顶部就是正在执行的函数, 下方都是它的父函数.
x 轴表示抽样数, 如果一个函数在 x 轴占据的宽度越宽, 就表示它被抽到的次数多, 即执行的时间长.
注意, x 轴不代表时间, 而是所有的调用栈合并后, 按字母顺序排列的.火焰图就是看顶层的哪个函数占据的宽度最大. 只要有 “平顶”(plateaus), 就表示该函数可能存在性能问题。