首先需要掌握GC相关的VM参数,会基本的空间调整
在java 安装目录下:查看相关的GC参数
调优跟应用,环境有关。并没有实际准则。
调优领域
确定目标
- 低延迟(互联网项目) 还是 高吞吐量(科学计算项目),选择合适的回收器。
- CMS , G1 , ZGC(java 12)
- ParallelGC
最快的GC 是不发生GC
- 查看FullGC 前后的内存占用(查看是不是自己代码问题)
- 数据是不是太多?
- 数据是否臃肿,存在非必须数据
- 对象大小问题,最小的object要占16字节
- 代码中,是否存在内存泄露?
新生代调优
新生代的特点:
所有的new操作的内存分配非常廉价,TLAB thread-local allocation buffer 用于存放线程信息,让每个线程用自己私有的这块Eden内存区域进行对象内存分配。这样不会对线程之后产生干扰。
死亡对象的回收代价是0
大部分对象用过即死
MinorGC 的时间远远低于 Full GC
如何调优:
-Xmn // 设置新生代大小 , 官方推荐: 新生代占 堆总大小的 25%~50%
- 并不是越大越好,太小的话会频繁的Minor GC。要是太大 , 老年代空间必然减少,新生代的垃圾回收触发少了,但是到一定时间之后,老年代会频繁触发垃圾回收(Full GC 时间 > MinorGC时间)。
- 新生代空间大小,和吞吐量的关系,有一个平衡值,当超过某个值时,吞吐量会跟随空间大小增加而下降。
- 新生代采用的标记复制算法,对于新生代来说,很多对象都是 朝生夕死,将幸存对象拷贝到幸存区。新生代的大小并不会影响到拷贝速度。
- 新生代大小,一般来说。 新生代大小 = 【并发量 * (一次请求响应过程中产生的对象)】的数据
- 幸存区大小,幸存区大小 = 能够保留 当前活跃对象(Eden区中可能晋升的对象,这些活跃对象都有可能进入幸存区) + 需要晋升的对象(在幸存区中没有达到晋升条件的对象)
新生代幸存区调优:
晋升阈值配置得当,让长时间存活对象尽快晋升。
-XX:MaxTenuringThreshold=threshold // 设置晋升阈值
-XX:+PrintTenuringDistribution // 查看各个 年龄段对象占的空间大小
老年代调优
以CMS为例:
- CMS的老年代内存越大越好
- 先尝试不做调优,如果没有Full GC那么可以不用调优老年代,先尝试调试新生代。
- 观察发生Full GC时老年代内存占用,将老年代内存预设调大 1/4 ~ 1/3
- -XX:CMSInitiatingOccupancyFraction=percent // 75% ~80%