JVM调优

知识库编程技巧JavaJava大约 5 分钟

jvm调优本质和原则

  • JVM调优本质就是 gc , 垃圾回收,及时释放内存空间
  • gc的时间足够小(堆内存设置足够小)
  • gc的次数足够少(jvm堆内存设置的足够大)
  • 发生fullgc 周期足够长 (最好不发生full gc)
    • metaspace 永久代空间设置大小合理,metaspace一旦扩容,就会发生fullgc
    • 老年代空间设置一个合理的大小,防止full gc
    • 尽量让垃圾对象在年轻代被回收(90%)
    • 尽量防止大对象的产生,一旦大对象多了以后,就可能发生full gc ,甚至oom

清除垃圾算法

  1. mark-sweep [标记清楚算法]

    • 使用根可达算法找到垃圾对象,对垃圾对象进标记 (做一个标记)
    • 对标记对象进行删除(清除)
      优点: 简单,高效
      缺点: 清除的对象都不是一个连续的空间,清除垃圾后,产生很多内存碎片;不利于后期对象内存分配,及寻址;
  2. copying [拷贝算法]

    • Copying 拷贝算法: 一开始就把内存控制一份为2,分为2个大小相同的的内存空间,另一半空间展示空闲;
  • 选择(寻址)存活对象
  • 把存活对象拷贝到另一半空闲空间中,且是连续的内存空间
  • 把存储对象拷贝结束后,另一半空间中全是垃圾,直接清除另一半空间即可;
    优点: 简单,内存空间是连续的,不存在内存空间碎片
    缺点: 内存空间浪费
  1. 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组合

  1. 吞吐量优先

并行的垃圾回收器: parallel scavenge(年轻代) + parallel old(老年代) ---- 是JDK默认的垃圾回收器
显式的配置PS+PO垃圾回收器:-XX:+UseParallelGC -XX:+UseParallelOldGC

  1. 响应时间优先

并行垃圾回收器(年轻代),并发垃圾回收器(老年代) : ParNew + CMS (响应时间优先垃圾回收器)
显式配置:parNew+CMS垃圾回收器组合:-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
说明: CMS只有再发生fullgc的时候才起到作用,CMS一般情况下不会发生;因此在jvm调优原则中表示尽量防止发生fullgc;
因此CMS在JDK14被已经被废弃;

  1. G1

G1 垃圾回收器是逻辑上分代模型,使用配置简单; -XX:+UseG1GC 经过测试,发现g1 gc次数减少,由原来的28次减少为21次,但是gc总时长增加很多;时间增加,以为着服务性能就没有提升上去;