预备知识
- 掌握 GC 相关的 VM 参数,会基本的空间调整
- 掌握相关工具
- 明白一点:调优跟应用、环境有关,没有放之四海而皆准的法则
查看虚拟机参数命令
D:\JavaJDK1.8\bin\java -XX:+PrintFlagsFinal -version | findstr "GC"
1)调优领域
- 内存
- 锁竞争
- cpu 占用
- io
- gc
2)确定目标
- 低延迟/高吞吐量? 选择合适的GC
- CMS G1 ZGC
- ParallelGC
- Zing
3)最快的 GC
答案是不发生 GC
-
首先排除减少因为自身编写的代码而引发的内存问题。
-
查看 Full GC 前后的内存占用,考虑以下几个问题。
数据是不是太多? resultSet = statement.executeQuery(“select * from 大表 limit n”)
数据表示是否太臃肿
对象图
对象大小 16 Integer 24 int 4
是否存在内存泄漏
static Map map …
软
弱
第三方缓存实现
4)新生代调优
-
新生代的特点
- 所有的 new 操作分配内存都是非常廉价的
- TLAB thread-lcoal allocation buffer
- 死亡对象回收零代价
- 大部分对象用过即死(朝生夕死)
- Minor GC 所用时间远小于 Full GC
- 所有的 new 操作分配内存都是非常廉价的
-
新生代内存越大越好么?
- 不是
- 新生代内存太小:频繁触发 Minor GC ,会 STW ,会使得吞吐量下降
- 新生代内存太大:老年代内存占比有所降低,会更频繁地触发 Full GC。而且触发 Minor GC 时,清理新生代所花费的时间会更长
-
新生代内存设置为内容纳[并发量*(请求-响应)]的数据为宜
-
幸存区需要能够保存 当前活跃对象+需要晋升的对象
-
晋升阈值配置得当,让长时间存活的对象尽快晋升
-XX:MaxTenuringThreshold=threshold -XX:+PrintTenuringDistrubution
5)老年代调优
以 CMS 为例:
-
CMS 的老年代内存越大越好
-
先尝试不做调优,如果没有 Full GC 那么已经可以了,否者先尝试调优新生代。
-
观察发现 Full GC 时老年代内存占用,将老年代内存预设调大 1/4 ~ 1/3
-
-XX:CMSInitiatingOccupancyFraction=percent
6)案例
案例1:Full GC 和 Minor GC 频繁
案例2:请求高峰期发生 Full GC,单次暂停时间特别长(CMS)
案例3:老年代充裕情况下,发生 Full GC(jdk1.7)