JVM调优
大约 5 分钟
jvm调优本质和原则
- JVM调优本质就是 gc , 垃圾回收,及时释放内存空间
- gc的时间足够小(堆内存设置足够小)
- gc的次数足够少(jvm堆内存设置的足够大)
- 发生fullgc 周期足够长 (最好不发生full gc)
- metaspace 永久代空间设置大小合理,metaspace一旦扩容,就会发生fullgc
- 老年代空间设置一个合理的大小,防止full gc
- 尽量让垃圾对象在年轻代被回收(90%)
- 尽量防止大对象的产生,一旦大对象多了以后,就可能发生full gc ,甚至oom
清除垃圾算法
mark-sweep
[标记清楚算法]- 使用根可达算法找到垃圾对象,对垃圾对象进标记 (做一个标记)
- 对标记对象进行删除(清除)
优点: 简单,高效
缺点: 清除的对象都不是一个连续的空间,清除垃圾后,产生很多内存碎片;不利于后期对象内存分配,及寻址;
copying
[拷贝算法]- Copying 拷贝算法: 一开始就把内存控制一份为2,分为2个大小相同的的内存空间,另一半空间展示空闲;
- 选择(寻址)存活对象
- 把存活对象拷贝到另一半空闲空间中,且是连续的内存空间
- 把存储对象拷贝结束后,另一半空间中全是垃圾,直接清除另一半空间即可;
优点: 简单,内存空间是连续的,不存在内存空间碎片
缺点: 内存空间浪费
mark-compact
[标记整理(压缩)算法]
- 标记垃圾(只标记,不清除)
- 再次扫描内存空间(没有被标记的对象就是存活对象),找到存活对象,且把存活对象向内存一端进行移动(一端内存空间是连续的内存空间)-- 压缩,整理
- 当存活对象全部被移动到一端后,那么另一端全部是垃圾对象,清除即可;
垃圾回收器

- Serial Serial Old , parNew CMS , Parallel Scavenge Parallel Old 都属于物理分代垃圾回收器;年轻代,老年代分别使用不同的垃圾回收器;
- G1 在逻辑上进行分代的,进行在使用上非常方便,关于年轻代,老年代只需要使用一个垃圾回收器即可;
- ZGC ZGC是一款JDK 11中新加入的具有实验性质的低延迟垃圾收集器
- Shenandoah OpenJDK 垃圾回收器
- Epsilon 是Debug使用的,调试环境下:验证jvm内存参数设置的可行性
- Serial Serial Old: 串行化的垃圾回收器
- parNew CMS : 并行,并发的垃圾回收器
- Parallel Scavenge Parallel Old : 并行的垃圾回收器
常用的垃圾回收器组合:
- Serial + Serial Old: 串行化的垃圾回收器,适合单核心的cpu的服务情况
- parNew + CMS:响应时间优先组合
- Parallel Scavenge + Parallel Old : 吞吐量优先组合
- g1 : 逻辑上分代的垃圾回收器组合
典型参数设置
nohup java -Xmx4000m -Xms4000m -Xmn2g -Xss256k -jar jshop-web-1.0-SNAPSHOT.jar --spring.config.addition-location=application.yaml > jshop.log 2>&1 &
- -Xmx4000m
设置JVM最大堆内存(经验值:3500m – 4000m,内存设置大小,根据实际情况来进行设置的) - -Xms4000m
设置JVM堆内存初始化的值,一般情况下,初始化的值和最大堆内存值必须一致,防止内存抖动; - -Xmn2g
设置年轻代内存对象(eden,s1,s2) - -XX:NewRatio = 4
表示年轻代(eden ,s0,s1) 和老年代区域所占比值 1:4 - -Xss256k
设置线程栈大小,JDK1.5+版本线程栈默认是1MB, 相同的内存情况下,线程堆栈越小,操作系统创建的线程越多; - -XX:MetaspaceSize=256m
- -XX:SurvivorRatio=8
- -XX:MaxTenuringThreshold
设置的是年龄阈值,默认15(对象被复制的次数) - -XX:G1HeapRegionsize
G1Region块大小,在1MB到32MB之间,且为2的N次幂,即1MB,2MB,4MB,8MB,16MB,32MB。
- -XX:+PrintGCDetails
打印GC详细信息 - -XX:+PrintGCTimeStamps
打印GC时间信息 - -XX:+PrintGCDateStamps
打印GC日期的信息 - -XX:+PrintHeapAtGC
打印GC堆内存信息 - -Xloggc:gc.log
把gc信息输出gc.log文件中
问题: 根据什么标准判断参数设置是否合理呢?? 根据什么指标进行调优呢??
1、发生几次gc, 是否频繁的发送gc??
2、是否发生fullgc ,full gc发生是否合理
3、gc的时间是否合理
4、oom
GC日志分析: 使用[https://gceasy.io](https://gceasy.io) 导入gc.log 进行在线分析即可;
# 查询此进程的gc内存模型;
jstat -gcutil PID
GC组合
- 吞吐量优先
并行的垃圾回收器: parallel scavenge(年轻代) + parallel old(老年代) ---- 是JDK默认的垃圾回收器
显式的配置PS+PO垃圾回收器:-XX:+UseParallelGC -XX:+UseParallelOldGC
- 响应时间优先
并行垃圾回收器(年轻代),并发垃圾回收器(老年代) : ParNew + CMS (响应时间优先垃圾回收器)
显式配置:parNew+CMS垃圾回收器组合:-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
说明: CMS只有再发生fullgc的时候才起到作用,CMS一般情况下不会发生;因此在jvm调优原则中表示尽量防止发生fullgc;
因此CMS在JDK14被已经被废弃;
- G1
G1 垃圾回收器是逻辑上分代模型,使用配置简单; -XX:+UseG1GC 经过测试,发现g1 gc次数减少,由原来的28次减少为21次,但是gc总时长增加很多;时间增加,以为着服务性能就没有提升上去;