GC 调优
查看虚拟机参数命令
"C:\Program Files\Java\jdk1.8.0_181\bin\java" -XX:+PrintFlagsFinal -version | findstr "GC"
可以根据参数去查询具体的信息
调优领域
- 内存
- 锁竞争
- CPU占用
- IO
- GC
确定目标
- 低延迟/高吞吐量? 选择合适的GC
- 科学运算追求高吞吐量(ParallelGC)
- 互联网项目需要追求低延迟((CMS G1 ZGC))
- 确定目标选择合适垃圾回收器
最快的GC是不发生GC
首先排除减少因为自身编写的代码而引发的内存问题
- 查看Full GC前后的内存占用,考虑以下几个问题
- 数据是不是太多?
- 类似于resultSet = statement.executeQuery(“select * from 大表”),这样数据太多,不建议这样的sql语句,一般来说可以加个分页
- 数据表示是否太臃肿
- 对象图
- 对象大小(Object16字节,Integer 24,int 4)
- 是否存在内存泄漏
- 例如静态map对象,加数据不移除,这种长时间的对象建议用软引用或弱引用或者直接用第三方缓存实现(redis等)
- 数据是不是太多?
新生代调优
- 新生代的特点
- 所有的new操作分配内存都是非常廉价的
- TLAB
- 死亡对象回收零代价
- 大部分对象用过即死(朝生夕死)
- MInor GC 所用时间远小于Full GC
- 所有的new操作分配内存都是非常廉价的
- 新生代内存越大越好么?
- 不是
- 新生代内存太小:频繁触发Minor GC,会STW,会使得吞吐量下降
- 新生代内存太大:老年代内存占比有所降低,会更频繁地触发Full GC。而且触发Minor GC时,清理新生代所花费的时间会更长
- 新生代内存一般大于堆25%,小于堆50%(官方建议)
- ,不过一般情况下还是调大一些,新生代内存设置为内容纳[并发量*(请求响应过程中产生对象的大小)]的数据为宜
- 不是
幸存区调优
- 幸存区需要大到能够保存 当前活跃对象+需要晋升的对象
- 晋升阈值配置得当,让长时间存活的对象尽快晋升
老年代调优
以CMS为例
- CMS的老年代内存尽可能的大
- 先尝试不做调优,如果没有full gc 那么说明很充裕,即使发生full gc也应优先调整新生代,如果还不行,则调老年代
- 观察发生full gc 时老年代内存占用,将老年代内存预设调大1/4~1/3
- -XX:CMSInitiatingOccupancyFraction=percent
- 一般75%到80%之间