jvm调优
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
参考
应用需求
IO应用计算应用
IO要求低延迟应用增加响应速度减少暂停时间
比如一致诟病的Android手机响应速度慢指的是用户点击APP图表到应用程序打开这段响应时间很长需要着重减少单次GC的时间不能在用户操作手机的过程中一次GC的时间过长。
对于涉及大量用户操作的系统对外提供接口的系统IO要求都较高都尽量要求响应速度需要GC重点减少单次GC的时间减少GC暂停时间
计算要求高吞吐量应用提高吞吐量
算法重复创建对象长时间存在的对象少
较大年轻代较小的老年代减少触发minor GC单位时间内的暂停时间最短
对于AI等算法应用其中涉及到大量计算计算要求都较高都尽量提高单位时间内计算线程运行的时间需要GC重点减少单位时间内GC的时间提高吞吐量
调优层次
架构调优优先
代码调优优先
JVM调优其次
数据库调优
操作系统调优
调优指标
GC频率GC时间
GC频率GC时间
时间计算时间IO时间空间
吞吐量=应用线程运行时间/(应用线程运行时间+GC线程运行时间)
暂停时间GC时工作线程被暂停的时间
内存占用堆区内存大小
不可能三角一款优秀的GC最多同时满足其中两项
- 吞吐量单位时间内GC时间短
- 暂停时间单次GC时间短
设计/使用GC时
- 专注较大吞吐量或最小暂停时间
- 最大吞吐量和最小暂停时间的折衷
GC
GC | 串并行发 | 作用位置 | 算法 | 特点 | 场景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 复制算法 | 响应速度 | 单CPU环境下client模式 |
ParNew | 并行 | 新生代 | 复制算法 | 响应速度 | 多CPU环境下Server模式下与CMS配合使用 |
Parallel | 并行 | 新生代 | 复制算法 | 吞吐量 | 多运算少IO |
Serial Old | 串行 | 老年代 | 标记-整理 | 响应速度 | 单CPU环境下client模式 |
Parallel Old | 并行 | 老年代 | 标记-整理 | 吞吐量 | 多运算少IO |
CMS | 并发 | 新生代老年代 | 标记-清除 | 响应速度 | B/S业务 |
G1 | 并发并行 | 新生代老年代 | 复制算法、标记-整理 | 响应速度 | 服务端应用 |
ZGC | 新生代老年代 | 复制算法 | 服务端应用 |
GC概念
概念 | 针对 | gc |
---|---|---|
young gc/minor gc | 年轻代的gc | |
old gc/major gc | 老年代gc | CMS |
full gc | 新生代、老年代、元空间gc | |
mixed gc | 年轻代、部分老年代gc | G1 |
GC算法
标记-清除
过程最初的算法先标记再清除
优点基础算法
缺点新生代大多数对象都是朝生夕死死亡对象多标记对象多清除对象多执行次数越多效率越低
效率随对象数量增多而下降产生大量外部碎片
使用CMS使用该算法收集老年代的垃圾
标记-复制算法
过程内存分成两个区域第1个区域使用完了把幸存对象复制到第2个区域再清空第1块内存
优点主要应用于新生代
缺点另一部分空间始终空闲Eden区幸存对象无法放入s区需要分配担保策略直接进入老年代
使用Serial、ParNew、Parallel
标记-整理
背景标记-复制算法不适用与老年代存在大量幸存对象的情况
过程往内存的一端移动清理掉边界以外的内存
优点解决标记-清除算法的外部碎片问题解决标记-复制算法需要分配担保的问题
使用Serial Old、Parallell Old
标记-清除
标记-整理
对比 标记-清除 和 标记-整理
算法 | 移动 | 内存 |
---|---|---|
标记-清除 | 对象不移动 | 内存分配复杂 空间碎片化触发GC对象分配依赖于“空闲列表”对象分配阶段耗时 |
标记-整理 | 对象移动 | 内存回收复杂 老年代大部分对象存活GC时伴随大量的对象移动对象回收阶段耗时 |
GC/Serial, ParNew, Parallel
都关注新生代都使用标记-复制算法因为新生代大部分对象都死的快需要复制的对象少效率就高
GC/CMS, Serial Old, Parallel Old
都关注老年代老年代大部分对象都存活
使用标记-整理算法内存分配时间短回收时间长
使用标记-清除算法内存分配时间长回收时间短
GC/CMS
GC/G1
面向服务端应用针对具有大内存、多处理器的机器在普通大小的堆里表现并不惊喜
需要低GC延迟并有大堆的应用程序(G1“增量式清理”来保证每次GC停顿时间不会过长)
在堆大小约6GB或更大时可预测的暂停时间可以低于0.5秒
转移阶段要处理所有存活的对象耗时会较长。因此G1停顿时间的瓶颈主要是标记-复制中的转移阶段STW。为什么转移阶段不能和标记阶段一样并发执行呢主要是G1未能解决转移过程中准确定位对象地址的问题。
与ZGC对比G1的转移阶段完全STW的且停顿时间随存活对象的大小增加而增加。
GC/ZGC
JDK11
停顿时间不超过10ms
停顿时间不会随着堆的大小或者活跃对象的大小而增加
支持8MB~4TB级别的堆未来支持16TB
转移阶段也是并发执行的
ZGC几乎所有暂停都只依赖于GC Roots集合大小停顿时间不会随着堆的大小或者活跃对象的大小而增加。与ZGC对比G1的转移阶段完全STW的且停顿时间随存活对象的大小增加而增加。
jdk/GC
jdk各个版本默认GC
jdk版本 | 默认GC | 新生代GC | 老年代GC |
---|---|---|---|
jdk7u4- | Parallel Scavenge + Serial Old | Parallel Scavenge | Serial Old |
jdk7u4+ | Parallel Scavenge + Parallel Old | Parallel Scavenge | Parallel Old |
jdk8 | Parallel Scavenge + Parallel Old | Parallel Scavenge | Parallel Old |
jdk11 | G1 | G1 | G1 |
jdk17 | 默认GC | 新生代GC | 老年代GC |
jdk21 | 默认GC | 新生代GC | 老年代GC |
jvm参数对应gc
参数 | 代表GC |
---|---|
-XX:-UseSerialGC | Serial + Serial Old |
-XX:-UseParNewGC | ParNew + Serial Old |
-XX:-UseParallelGC | Parallel Scavenge + Serial Old |
-XX:-UseParallelOldGC | Parallel Scavenge + Parallel Old |
-XX:-UseConcMarkSweepGC | CMS + ParNew |
-XX:-UseG1GC | G1 |
参数 | 代表GC |
jdk7/GC
命令java -XX:+PrintCommandLineFlags -version
结果-XX:+UseParallelGC
JDK 7u4-
- server模式默认采用 Parallel Scavenge + Serial Old(PS MarkSweep)
- 新生代用 Parallel Scavenge 老年代用 Serial Old
JDK 7u4=+
- server模式默认采用 Parallel Scavenge + Parallel Old(PS MarkSweep)
- 新生代用 Parallel Scavenge 老年代用 Parallel Old
jdk8/GC
server模式默认采用 Parallel Scavenge + Parallel Old(PS MarkSweep)
新生代用 Parallel Scavenge 老年代用 Parallel Old
jdk11/GC
命令java -XX:+PrintCommandLineFlags -version
结果-XX:+UseG1GC
server模式默认采用 G1
jdk17/GC
jdk21/GC
调整
堆
-Xms 等于 -Xmx 建议扩大3-4倍FullGC后老年代空间大小
过小频繁GC
过大GC时间过长
堆/新生代
-Xmn1-1.5倍FullGC之后的老年代空间占用
过小minor GC次数频繁对象直接进入老年代触发Full GC时工作线程被暂停的时间
过大老年代变小Full GC频繁执行minor GC增加回收时间
堆/老年代
老年代使用并发收集器
方法区/元空间
-XX:MetaspaceSize 等于 -XX:MaxMetaspaceSize
1.2-1.5倍 Full GC后的元空间占用
调优过程
生成GC日志/dump文件/第三方可视化工具
分析判断
参数设置合理性
异常信息
GC频率
GC耗时GC超过1秒必须优化
吞吐量或响应时间异常
堆/老年代 持续上涨
确定目标
使用最小的硬件消耗来承载更大的吞吐量和更低的响应时间
- 堆内存使用率 <=70%
- 老年代内存使用率 <=70%
- 平均停止时间 <=1s
- Full GC调用次数接近于0 或 两次GC时间间隔>=24h