虚拟机6-调优
# 优化参数
JVM调优,主要调三块:一是堆内存大小,二是选垃圾收集器,三是年轻代大小。
但先说个前提:别一出问题就调参数,先查代码!内存溢出、奇怪问题,多半是代码漏了资源没关,就像篱笆破了羊跑了,光抓羊不修篱笆没用。调优前,确保代码没内存泄漏,再根据业务场景调,不然你就是在瞎搞!!!
调优得有数据,得加监控,收集性能数据,再动手。那怎么调?看这几步:
第一,选项基础。JVM参数分三类:
-
(如-version
),标准选项,任何JVM都认,没兼容问题。-X
(如-Xms
),非标准但主流JVM都支持,基本稳定。-XX
(如-XX:+PrintGCDetails
),不稳定参数,不同版本支持不同,随时可能废,用前查文档。加号开,减号关,记住了。
第二,实战建议。
垃圾收集器:我推荐G1。JDK 1.8就有,1.9默认,用
-XX:+UseG1GC
开就行。为啥选G1?简单、智能、不分代是趋势,参数少,Oracle敢默认放到1.9用。堆大小:
-Xms
和-Xmx
设一样,比如2GB起步,避免运行时动态调整,省开销。- 怎么定大小?上线时设大点,跑几天看监控日志,找堆峰值,乘2或3就够了。
- 日志咋开?用
-Xloggc:logs/gc.log
设路径,-XX:+PrintGCTimeStamps
看时间,-XX:+PrintGCDetails
看详情
线程栈:
-Xss256k
。默认1MB太浪费,高并发下几千线程,内存扛不住。普通业务128k够,复杂点256k也行。若不够,检查代码,别指望调大解决问题。栈只存指针,256k装不下那就是程序的问题,效率早崩了。G1停顿:
-XX:MaxGCPauseMillis=500
。G1默认200毫秒停顿上限,调到500毫秒,多给点时间回收更多垃圾,减少GC次数,提升吞吐量。副作用是延迟高点,但半秒延迟用户感知不大,按业务调就行。
# Best Practice
这里做一个小总结
java -jar -XX:+UseG1GC -Xms2G -Xmx2G -Xss256k -XX:MaxGCPauseMillis=300 -Xloggc:/logs/gc.log -XX:+PrintGCTimeStamps -XX:+PrintGCDetails test.jar
## 参考配置参数
-XX:+UseG1GC -Xms2G -Xmx2G -Xss256k -XX:MaxGCPauseMillis=300 -Xloggc:/logs/gc.log -XX:+PrintGCTimeStamps -XX:+PrintGCDetails
-Xss200k -Xms2g -Xmx2g -XX:MaxGCPauseMillis=100 -XX:G1HeapRegionSize=4m -XX:+UseG1GC -XX:ReservedCodeCacheSize=512m -XX:+AlwaysPreTouch
1
2
3
4
5
6
2
3
4
5
6
调优别瞎搞,先修代码,再看场景。G1配好堆和栈,日志监控定大小,停顿微调到500毫秒,基本够用。
# JVM监控
命令 | 说明 | 常用格式 | 注意点 |
---|---|---|---|
jps | 查看Java进程PID | jps | 简单高效,替代ps 和netstat |
jinfo | 查看JVM环境与参数 | jinfo 3669 > out.txt | 静态数据,可存档分析 |
jstat | 查看JVM内存及GC状态 | jstat -gcutil 3669 1000 10 | 可改-gc 看数值,或脚本长期跑 |
jstack | 查看各线程调用方法堆栈 | jstack -l 3669 | 线程多时需配合工具,不直接看 |
jmap | 生产统计+ 生成堆dump文件 | jmap -histo 3669 | head -n 20 jmap -dump:live,format=b,file=dump.hprof 3669 | 调优排错关键,live只dump存活对象 |
jhat | dump分析工具 | jhat dump.hprof | 生产环境不推荐,安全性差 |
完善页面 (opens new window)