性能与调优
一. JDK 命令行工具
1. 内存分配和回收 - GC 日志解读
1. 默认 JVM 不会打印出 GC 日志信息,可以通过参数来设置 JVM 输出 GC 日志到终端中
JVM 参数:
-Dcom.sun.management.jmxremote=true (JMX 管理功能, 部分 JVM 工具是基于 JMX 的, 所以要开启此选项)
-XX:+PrintGCTimeStamps(打印GC停顿时间)
-XX:+PrintGCDetails(打印GC详细信息)
-verbose:gc(打印GC信息,输出内容已被前一个参数包括,可以不写)、-Xloggc:gc.log
2. GC 日志案例
33.125: [GC [DefNew: 3324K->152K(3712K), 0.0025925 secs] 3324K->152K(11904K), 0.0031680 secs]
100.667: [Full GC [Tenured: OK->210K(10240K), 0.0149142 secs] 4603K->210K(19456K), [Perm : 2999K->2999K(21248K)], 0.015007 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
3. GC 日志规则
33.125、100.667
表示 GC 发生时间, 从 JVM 虚拟机启动后, 发生 GC 的秒数
[GC、[Full GC
表示 GC 的停顿类型, 如果有 Full GC 表示发生了 Stop The World, 如果是通过调用 System.gc() 则会显示成 [Full GC(System)
[DefNew、[Tenured、[Perm
表示 GC 发生的区域
DefNew: 表示使用新生代收集器 Serial
ParNew: 表示使用新生代收集器 ParNew
PSYoungGen: 表示使用新生代收集器 Parallel Scavenge
年老代同理
[DefNew: 3324K->152K(3712K), 0.0025925 secs] 3324K->152K(11904K), 0.0031680 secs
表示 GC 区域、GC 堆的容量和耗时信息
方括号 [] 之内, 表示区域 DefNew 的内存回收情况
方括号 [] 之外, 表示堆的内存回收情况
[DefNew: 3324K -> 152K (3712K) , 0.0025925 secs] 3324K -> 152K (11904K), 0.0031680 secs
[DefNew: GC 前内存区域容量 -> GC 后的区域容量 (区域总容量), GC 耗时秒数 GC 前堆容量 -> GC 后堆容量 (堆总容量) GC 总耗时秒数
[Times: user=0.01 sys=0.00, real=0.02 secs]
表示 GC 的详细时间, 与 Linux 的 time 命令含义一致
user: 用户态消耗的 CPU 时间, 当系统有多个 CPU 或者多核, 多线程操作会叠加这些 CPU 时间, 所以 user 或者 sys 超过 real 时间很正常
sys: 内核态消耗的 CPU 事件
real: 操作从开始到结束所经过的樯钟时间(Wall Clock Time), 与 CPU 时间的区别是: 樯钟时间包括各种非运算的等待耗时(等待磁盘 I/O、等待线程阻塞), CPU 时间则不包含这些
二. JDK 命令行工具
1. jps
- 虚拟机进程状况工具, 显示所有 HotSpot 虚拟机运行的进程
jps [ option ] [ hostid ]
jps -l 显示主类全名和路径
jps -v 显示虚拟机进程启动时, 传递给 JVM 参数
jps -m 显示虚拟机进程启动时, 传递给主类 main() 函数的参数
jps -q 只显示 LVMID
2. jstat
- 虚拟机统计信息监控工具, 收集 HotSpot 虚拟机各方面的运行参数
- 显示本地或者远程虚拟机进程中的类装在、内存、垃圾收集、JIT 编译等运行数据
jstat [ option vmid [ interval[s|ms] [count] ] ]
vmid : VMID 格式: 进程 ID
LVMID 格式: [protocol:][//]lvmid[@hostname[:port]/servername]
interval: 查询间隔
count: 查询次数
jstat -gc [vmid] 1s 5
监控 Java 堆状况, 包括 Eden 区域、survivor 两个、老年代、永久代等的容量、已用时间、GC 时间合计等信息
jstat -gccapacity [vmid]
同 -gc, 但主要显示 Java 堆各个区域使用到的最大、最小空间
jstat -gcutil [vmid]
同 -gc, 但主要显示已使用空间占总空间的百分比
jstat -gccause [vmid]
同 -gcutil, 但是会显示上一次 GC 产生的原因
jstat -gcnew [vmid]
监控新生代 GC
jstat -gcnewcapacity [vmid]
同 -gcnew, 但主要显示区域使用到的最大、最小空间
jstat -gcold [vmid]
显示老年代 GC 信息
jstat -gcoldcapacity [vmid]
同 -gcold, 但主要显示区域使用到的最大、最小空间
jstat -gcpermcapacity [vmid]
显示永久代区域使用到的最大、最小空间
日志字段解读:
1) -gccause 堆比例显示的参数
S0 (Survivor0 使用百分比)
S1 (Survivor1 使用百分比)
E (Eden 使用百分比)
O (Old 使用百分比)
P (Permanent 永久代使用百分比)
YGC (Young GC 或 Minor GC 总次数)
YGCT (YGC 总耗时秒)
FGC (Full GC 总次数)
FGCT (Full GC 总耗时秒)
GCT (所有 GC 耗时)
GCC (上一次 GC 原因)
2) -gcpermcapacity 永久代显示的大小参数
PGCMN 最小永久代
PGCMX 最大永久代
PGC
PC
YGC
FGC
FGCT
GCT
3) -gcnewcapacity 新生代显示的大小参数
NGCMN 最小新生代
NGCMX 最大新生代
NGC
S0CMX
S0C
S1CMX
S1C
ECMX
EC
YGC
FGC
4) -gcoldcapacity 老年代显示的大小参数
OGCMN
OGCMX
OGC
OC
YGC
FGC
FGCT
GCT
3. jinfo
- Java 配置信息工具, 显示虚拟机配置信息
- 动态修改虚拟机的配置
jinfo [ option ] pid
jinfo -sysprops [pid]
显示运行时参数
jinfo -flag[+|-] | -flag name=value
修改部分运行期间可写的参数
例如: jinfo -flag CMSInitiatingOccupancyFraction [pid]
jinfo -flag MaxGCPauseMillis [pid]
4. jmap
- Java 内存印像工具, 生成虚拟机的内存转储快照(heapdump) 文件
- 查询 finalize 执行队列、Java 堆和永久代信息, 空间使用率、当前使用的 GC 回收期等信息
-XX:+HeapDumpOnOutOfMemoryError
如果不使用 jmap 工具, 可通过开启此选项在 JVM OOM 异常后生成 heapdump 文件
-XX:+HeapDumpOnCtrlBreak
使用快捷键 [Ctrl]+[Break] 让虚拟机生成 heapdump 文件
jmap [option] vmid
jamp -heap vmid
kill -3 命令发送退出信号, 提醒 JVM 一下, 也能拿到 heapdump 文件
5. jhat
- 虚拟机堆转储快照分析工具, 用于分析 heapdump 文件, 会建立一个 HTTP/HTML 服务器, 可以在浏览器查看分析结果
6. jstack
- Java 堆栈跟踪工具, 显示虚拟机的线程快照
7. HSDIS
- JIT 生成代码反汇编
二. JDK 可视化工具
可视化工具参数
## JMX 管理功能, 部分 JVM 工具是基于 JMX 的, 所以要开启此选项
-Dcom.sun.management.jmxremote=true
## 指定了JMX启动的代理端口,这个端口就是visualvm要连接的端口(9998端口不能被别的程序使用netstat -an|gerp 9998)
-Dcom.sun.management.jmxremote.port=[port]
# 指定了JMX是否启用ssl
-Dcom.sun.management.jmxremote.authenticate=false
# 指定了JMX是否启用鉴权(需要用户名,密码鉴权)
-Dcom.sun.management.jmxremote.authenticate=false
# 指定服务器主机名
-Djava.rmi.server.hostname=appNtest
1. JConsole
- Java 监视与管理控制台
# 1. Java 启动时, 增加如下参数, 程序会开启 TCP 端口 9100, 使用 JConsole 连接即可. (具体 Java 程序根据情况定义, 这里是一个案例)
java -Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.port=9100 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Dfile.encoding=UTF-8 \
-jar ~/app/dw_general_loader/run/dw_general_loader.jar dim_product_kpi 2018-02-27
# 2. Java 客户端工具, 用于界面显示 Java 程序运行是的变化
## 命令行方式启动
$JAVA_HOME/bin/jconsole ip:port
## 启动界面, 输入远程连接即可
$JAVA_HOME/bin/jconsole
# 3. PS 注意一点, 如果提示需要密码文件, 需要给与 chmod 600 权限
chmod 600 $JAVA_HOME/jre/lib/management/jmxremote.password
2. VisualVM
- Java 多合一故障处理工具
# 1. 程序启动监控
java -Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.port=9200 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dfile.encoding=UTF-8 \
-jar ~/app/dw_general_loader/run/dw_general_loader.jar dim_product_kpi 2018-02-27
# 2. Java 客户端工具, 用于界面显示 Java 程序运行是的变化
$JAVA_HOME/bin/jvisualvm
3. jstatd
- 使用 jstatd 监控目标主机上的所有 jvm 进程
# 1. 配置策略文件
## 创建策略目录
mkdir -p $JAVA_HOME/policy
## 编辑策略文件 jstatd.all.policy, 写入如下信息
vim $JAVA_HOME/policy/jstatd.all.policy
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
# 2. 启动 jstatd 守护进程
$JAVA_HOME/bin/jstatd -J-Djava.security.policy=$JAVA_HOME/policy/jstatd.all.policy -p 9300
# 3. 连接器使用 VisualVM
$JAVA_HOME/bin/jvisualvm
4. 插件
由于插件迁移到了 github, 新地址 可用插件的地址, 根据 JDK 版本选择插件版本
Visual GC
BTrace