当前位置: 首页 > news >正文

【开发篇】十三、JVM基础参数设置与垃圾回收器的选择

文章目录

  • 1、-Xmx 和 –Xms
  • 2、-XX:MaxMetaspaceSize 和 –XX:MetaspaceSize
  • 3、-Xss
  • 4、不建议改的参数
  • 5、其他参数
  • 6、选择GC回收器的调试思路
  • 7、CMS的并发模式失败现象的解决
  • 8、调优案例

GC问题解决方式:

  • 优化JVM基础参数,避免频繁Full GC
  • 减少对象的产生,以免对象产生速度过快导致频繁Full GC
  • 选择适合业务场景的垃圾回收器
  • 优化垃圾回收器的参数

1、-Xmx 和 –Xms

-Xmx设置最大堆内存(max),-Xms设置可用堆内存大(total)

在这里插入图片描述
计算理论最大可用堆空间,如服务器内存4G,操作系统自己使用的内存+元空间最大值+其它软件占用1.5G ⇒ 理论最大可用堆空间为2.5g,只是理论值。(减去元空间是因为,Java 8及以后,元空间使用的是直接内存)

在这里插入图片描述
最后设置的堆内存大小,应是按照系统最大并发估计,且小于上面的理论值。最后,将-Xms设置的和-Xmx一样大,理由:

  • 可用内存一开始就等于最大堆内存,避免堆扩容时频繁向操作系统申请内存,影响程序性能
  • 避免扩容时,因其他应用占用了操作系统内存而申请扩容失败
  • 服务启动速度更快,初始堆太小(Xms太小),Java应用启动会变慢,因为JVM会被迫频繁垃圾回收,直到堆增长到一个合理的大小

2、-XX:MaxMetaspaceSize 和 –XX:MetaspaceSize

-XX:MaxMetaspaceSize :最大元空间。默认值比较大,万一元空间内存泄漏,会影响到操作系统(因为元空间用的直接内存)

–XX:MetaspaceSize:到这个值后,触发Full GC,后续什么值再触发,JVM自行计算。

在这里插入图片描述

3、-Xss

指定每个栈的大小,不指定取默认值,默认值取决于操作系统。如Linux x86 64bit 默认是1MB。如果没有方法的递归调用,可调小栈大小

//合理值为256k – 1m之间
-Xss256k

4、不建议改的参数

以下参数,调整可能会让某一个接口得益,但同时也会影响其他接口,不建议修改。

1-Xmn:年轻代的大小

年轻代的大小,默认为整个堆的1/3。可根据系统峰值计算年轻代大小,以尽量让对象只存在年轻代,不进入老年代(这样后面Young GC一下就行),但计算这个值的影响因素太多,不建议改。且G1垃圾回收器会动态调整年轻代的大小,更不建议改。

在这里插入图片描述

2)‐XX:SurvivorRatio 伊甸园区和幸存者区的大小比例,默认值为8

在这里插入图片描述

3)‐XX:MaxTenuringThreshold 最大晋升阈值

对象晋升有两个情况:

  • (GC一次,对象年龄+1)年龄 > 此值,进入老年代
  • 动态年龄判断机制:按年龄从小到大将对象空间加起来, > survivor区域的50%,就把大于等于该年龄的对象晋升到老年代

在这里插入图片描述

5、其他参数

-XX:+DisableExplicitGC作用:禁止在代码中调用System.gc()
-XX:+HeapDumpOnOutOfMemoryError作用:OOM时,生成hprof内存快照文件
-XX:HeapDumpPath=<path>作用:指定内存快照文件的生成路径
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:文件路径作用:JDK8及之前,打印GC日志
-Xlog:gc*:file=文件路径作用:JDK9及以后,打印GC日志


JVM参数模板总结:

-Xms1g
-Xmx1g
-Xss256k
-XX:MaxMetaspaceSize=512m 
-XX:+DisableExplicitGC
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/logs/my-service.hprof
# <=JDK8
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps# >=JDK9
-Xloggc:文件路径

6、选择GC回收器的调试思路

用以下代码模拟系统的业务代码进行压测:

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.SneakyThrows;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;@RestController
@RequestMapping("/fullgc")
public class DemoController {private Cache cache = Caffeine.newBuilder().weakKeys().softValues().build();private List<Object> objs = new ArrayList<>();private static final int _1MB = 1024 * 1024;//FULLGC测试结果://ps + po 50并发 260ms  100并发 474ms  200并发 930ms//cms -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 50并发 157ms  200并发 833ms//g1 JDK11 并发200 248@GetMapping("/1")public void test() throws InterruptedException {cache.put(RandomStringUtils.randomAlphabetic(8),new byte[10 * _1MB]);}}

创建一个具有弱引用键(value不存在了,可被GC回收)和软引用值的缓存对象(内存不足时,可GC回收),接口往里面放10M的数据,如此,不会OOM,且会较多触发FULL GC。用Jmeter并发/1接口的同时,再调用一次接口/2,用这个接口模拟有突发大对象产生时,对系统响应时间的影响:

@GetMapping("/2")
public void test() throws InterruptedException {ArrayList<Object> objects = new ArrayList<>();for (int i = 0; i < 1024; i++) {objects.add(new byte[3 * _1MB]);}
}

步骤:

  • Jmeter脚本压测,添加RT响应时间组件
  • 选择不同的垃圾回收器组合,测试50、100、200并发下,FULL GC对RT的时间的影响

统一JVM参数设置:

-Xms8g -Xmx8g -Xss256k -XX:MaxMetaspaceSize=512m  -XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/test.hprof  -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

测试的垃圾回收器组合:

  • ps + po
  • cms
  • JDK11的默认回收器g1

测试场景:

  • 高并发(/1接口)
  • 大对象产生(/2接口)

观察RT的结果:查看最大值,即接口的最大响应时间。峰值的出现,即FULL GC对接口响应时间的影响
在这里插入图片描述

7、CMS的并发模式失败现象的解决

CMS的垃圾清理线程和用户线程并行

在这里插入图片描述

如果并行清理的过程中,老年代的空间,不足以容纳新晋升到老年代的对象,就发生并发模式失败:

在这里插入图片描述

出现并发模式失败时,会导致JVM使用Serial Old单线程进行FULLGC回收老年代,这样会产生较长时间的停顿,从而影响接口响应时间。解决思路:

  • 减少对象的产生以及晋升
  • 增加堆内存大小
  • -XX:CMSInitiatingOccupancyFraction=

关于垃圾回收器的参数CMSInitiatingOccupancyFraction,当老年代大小达到其值,会自动进行CMS老年代垃圾回收。JDK8中,该值为-1,计算公式:

((100 - MinHeapFreeRatio) + (double)(CMSTriggerRatio * MinHeapFreeRatio) / 100.0)

最后,这个参数想生效,必须先开启:

-XX:+UseCMSInitiatingOccupancyOnly

调小这个值,比如从默认的90%调到60%,早些进行老年代的回收,就不会出现并发模式失败,也就不会有后面的Serial Old单线程回收老年代。

8、调优案例

案例背景:

  • 系统的接口在平时响应较快,但高峰期会出现调用时间较长的现象,现需要优化性能

分析的方向:

  • GC问题:查看是否出现连续的Full GC或者单次GC时间过长
  • 内存问题

步骤:

  • 生成GC报告,GcEasy分析
  • GC有问题,就调整参数或者换垃圾回收器
  • 内存有问题就jmap或Arthas将堆内存快照保存
  • MAT或者heaphero在线分析内存
  • 修复

关于heaphero:https://heaphero.io/

调优案例:https://www.bilibili.com/video/BV1r94y1b7eS?p=68&vd_source=d86e858b4dfd8944a691759448d35279

http://www.lryc.cn/news/339955.html

相关文章:

  • 多维 HighCharts
  • 单细胞RNA测序(scRNA-seq)cellranger count的细胞定量和aggr整合
  • Unity URP 2021 Release-Notes
  • 最新IntelliJ IDEA 2024.1 安装和快速配置教程
  • 24应届生求职中QAQ
  • centos7离线安装postgresql13
  • 【JavaSE】搞定String类
  • 数字乡村创新实践探索农业现代化与农村治理现代化新路径:科技赋能农村全面振兴与农民幸福生活
  • 【从零开始手搓12306项目】四、12306是如何成为全球最忙碌的网站之一?
  • WebKit简介及工作流程
  • 软考-系统集成项目管理中级--进度管理(输入输出很重要!!!本章占分较高,着重复习)
  • AndroidAutomotive模块介绍(一)整体介绍
  • 【开发问题记录】Nacos修改服务实例权重时报错
  • 高级IO和5种IO模型
  • OpenHarmony轻量系统开发【7】驱动之I2C显示OLED屏幕
  • C#:循环中断
  • 34. UE5 RPG实现鼠标点击移动
  • 《二》Qt Creator工具介绍与使用
  • 20240415金融读报:市场信贷不能过于宽松声音碳领域新增文件
  • 2024年第十五届蓝桥杯研究生组题目总结(Java、Python、C++)
  • MindOpt APL向量化建模语法的介绍与应用(2)
  • 深入理解图形处理器(GPU):加速人工智能和大数据计算的引擎
  • 【Java探索之旅】数组使用 初探JVM内存布局
  • RabbitMQ消息模型之Simple消息模型
  • 设计模式系列:简单工厂模式
  • 解决 windows+Ubuntu 时间不同步问题
  • Learn SRP 01
  • NL2SQL进阶系列(4):ConvAI、DIN-SQL、C3-浙大、DAIL-SQL-阿里等16个业界开源应用实践详解[Text2SQL]
  • Python统计分析库之statsmodels使用详解
  • A Learning-Based Approach for IP Geolocation(2010年)