跳至主要內容

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 [标记整理(压缩)算法]
  • 标记垃圾(只标记,不清除)
  • 再次扫描内存空间(没有被标记的对象就是存活对象),找到存活对象,且把存活对象向内存一端进行移动(一端内存空间是连续的内存空间)-- 压缩,整理
  • 当存活对象全部被移动到一端后,那么另一端全部是垃圾对象,清除即可;

垃圾回收器

yCY9iV
yCY9iV
  • 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 总时长增加很多;时间增加,以为着服务性能就没有提升上去