JVM调优—减少FullGC

背景

        最近负责了一个审批流程新项目,带领了几个小伙伴,哼哧哼哧的干了3个月左右,终于在三月底完美上线了,好消息是线上客户用的很丝滑,除了几个非常规的业务提单之外,几乎没有什么大的问题,但是美中不足的是,发现每个pod的GC频率非常高,基本上30分钟就会有一次FGC,导致每次流量高峰的时候,会有一部分客户反馈,系统有些卡顿,观察监控平台发现,每天流量高峰的时候FGC竟然达到了惊人的5分钟每次,每次GC的时间差不多有400-700ms,此时,部分接口的耗时达到了5s,因此接口优化和参数调优迫在眉睫;
        因为本项目是基础服务,每个业务方都会调用,所以当时申请节点内存大小的时候就富裕了一点,共部署了4个pod,每个pod资源是8核16G,但是观察监控平台发现,每个pod内存只使用不到2G,其中eden 200M old 500m survivor更是只有可怜的96m左右,导致年轻代很容易就占满了,存活的对象就被转移到老年代了,由于老年代分配的内存也特别少,QPS一高就会频繁的触发FullGC,导致系统卡顿甚至接口超时。
        排查代码发现有一个占比60%量一个接口虽然查询的表比较单一,但是查询了所有字段,其中一个字段存储的是一个JSON,但业务中却又没有使用到。

JVM常见参数

一、配置垃圾收集器

1、Serial垃圾收集器(新生代)

         开启:-XX:+UseSerialGC

         关闭:-XX:-UseSerialGC

         //新生代使用Serial  老年代则使用SerialOld

 ​

 2、ParNew垃圾收集器(新生代)

         开启 -XX:+UseParNewGC

         关闭 -XX:-UseParNewGC

         //新生代使用功能ParNew 老年代则使用功能CMS

 ​

 3、Parallel Scavenge收集器(新生代)

         开启 -XX:+UseParallelOldGC

         关闭 -XX:-UseParallelOldGC

         //新生代使用功能Parallel Scavenge 老年代将会使用Parallel Old收集器

 ​

 4、ParallelOld垃圾收集器(老年代)

        开启 -XX:+UseParallelGC

        关闭 -XX:-UseParallelGC

        //新生代使用功能Parallel Scavenge 老年代将会使用Parallel Old收集器

 ​

 5、CMS垃圾收集器(老年代)

        开启 -XX:+UseConcMarkSweepGC

        关闭 -XX:-UseConcMarkSweepGC

 ​

 6、G1垃圾收集器

         开启 -XX:+UseG1GC

         关闭 -XX:-UseG1GC

二、堆内存相关配置

设置堆初始值

         指令1:-Xms2g

 ​

 设置堆区最大值

         指令1:-Xmx2g

 ​

 新生代内存配置

         指令1:-Xmn512m

 ​

 2个survivor区和Eden区大小比率

         指令:-XX:SurvivorRatio=6  //S区和Eden区占新生代比率为1:6,两个S区2:6(默认是8,即8:1:1)

 ​

 新生代和老年代的占比

 -XX:NewRatio=4  //表示新生代:老年代 = 1:4 即老年代占整个堆的4/5;默认值=2

三、GC并行执行线程数

        -XX:ParallelGCThreads=16

四、进入老年代的GC年龄

         -XX:InitialTenuringThreshol=7 //年轻代对象转换为老年代对象最小年龄值,默认值7,对象在坚持过一次Minor GC之后,年龄就加1,每个对象在坚持过一次Minor GC之后,年龄就增加1

 ​

         -XX:MaxTenuringThreshold=15 //年轻代对象转换为老年代对象最大年龄值,默认值15

五、GC日志信息配置

        -Xloggc:/data/gclog/gc.log//固定路径名称生成

         -Xloggc:/home/GCEASY/gc-%t.log //根据时间生成

        打印GC的详细日志 

        开启 -XX:+PrintGCDetails

        关闭 -XX:-PrintGCDetails

六、在Full GC时生成dump文件

        -XX:+HeapDumpBeforeFullGC       //实现在Full GC前dump

        -XX:+HeapDumpAfterFullGC        //实现在Full GC后dump。

        -XX:HeapDumpPath=e:\dump        //设置Dump保存的路径


调优过程

    一、业务调优

       业务调优就不展开讲述了,主要是用到了arthas这个调优工具,trace了耗时比较久的接口,排除不优雅的编码之后,就来到了数据层面,由于项目使用的是postgres sql,并且已经分库+分区了,核心表的数据量级也是百万级别,所以最终关注的是索引,使用explain查看核心sql的执行计划,看其是否命中索引;

        补充一点,由于项目有一张历史表的数据量比较大,8000万左右,并且业务中也需要使用到,每个单据号对应的审批流程一般是流程节点的10倍左右,比如某个审批流程10个节点,那么改流程结束后就会产生100+条数据,在列表中使用到了改表中的某些数据,起初直接根据单据号进行查询,那么分页条数为1000的时候每次就会查询1000*100条记录,而业务真正需要关注的只是10个节点的审批结果而已,白白浪费90%的查询记录,因此,在业务中冗余了一个节点字段,标识是否是节点的审批结果,每次查询除了使用单据号之外,加上该字段,就大大的过滤了记录数量,这样做法有如下好处:

        ①减少网络传输量

        ②降低内存使用(起初是内存过滤,高cpu操作)

        ③防止OOM


二、JVM参数调优

        第一版

                第一版比较偷懒,直接上了G1,因此G1不用配置过多的参数,很多就自适应调节,但是一上线发现cpu就很容易飙升到80以上,并且接口耗时也慢了一倍,起初每个接口的耗时到该200ms,G1之后就变成400ms,终于在运行3天之后,就有监控告警有大量的接口请求超时,观察到jvm堆内存使用长时间100%,导致健康检查机制强行将节点重启了(5s检查一次,15未检查到就重启)为了不影响业务先增加了两个节点,降低QPS,从而降低堆内存使用。

                具体的参数配置

-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -XX:+PrintGC -Xloggc:/data/logs/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/ -XX:+UseG1GC -Xmx9G -Xms9G -XX:MaxDirectMemorySize=1g -XX:ConcGCThreads=8 -XX:MaxGCPauseMillis=500 

        第二版

        由于公司所有的项目都是K8s集群部署,所以JVM参数基本都用的是默认参数,这一次只是设置了Xms=11g,Xmx=10g,Xmn=4g,但是发现年轻代的from和to的比例不对,按照正常的默认8:1:1,应该是410m左右,但是监控上面显示的始终是121m,这样的话QPS达到高峰的时候,老年代上升的速率就比较快,3.76G,基本上12h就用完触发了FGC,这显然是不合理的,因为业务逻辑中没有需要常驻内存的对象,基本上朝生夕灭的,在年轻代就应该被回收,而导致出现这个原因是from和to的内存太小了,存货了15次之后的对象就被转移到老年代了。

        开始的时候使用-XX:-UseAdaptiveSizePolicy –XX:SurvivorRatio=8,确实改变年轻代的具体分配内存,但是使用 jmsp -heap 1命令发现,jvm的垃圾回收器是ParallelGC,并不是我们想要的CMS,因此不论年轻代from和to的设置了多大空间,其使用始终不会超过121m,老年代还是晋升的速率比较快,并没有彻底解决问题。具体参数配置如下

-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Xmx11g -Xms11g -Xmn5g -XX:PermSize=1g -XX:MaxPermSize=1g -XX:SurvivorRatio=8 -XX:-UseAdaptiveSizePolicy -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps

        第三版 最终版本

      开启CMS收集参数  -XX:+UseConcMarkSweepGC,监控和运行变得正常,堆空间各个区域的分配也是正常的。

-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -XX:+UseConcMarkSweepGC -Xmx11g -Xms11g -Xmn5g -XX:PermSize=1g -XX:MaxPermSize=1g -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:/data/logs/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs

        小结

        容器部署节点只分配1G,具体原因可以参考这篇文章频繁 GC 问题排查以及UseContainerSupport与MaxRAMPercentage的正确使用-CSDN博客

        按照理论上第二次调优就已经能够满足业务需求了,但是依据《深入理解Java虚拟机》讲的,jdk8默认的垃圾收集器是CMS,那么年轻代的eden、from和to分配内存空间的比例应该是8:1:1,显然目前我的数据不正确,进入到pod节点发现jvm使用的是ParallelGC,如下图所示


jvm调优常见问题

        常用命令

        jmap -heap pid 查看内存使用情况

推荐配置

        8C16G下的参数配置

综上所述,8C16G下,推荐使用如下的参数设置:

-Xmx12g -Xms12g

-XX:ParallelGCThreads=8

-XX:ConcGCThreads=2

-XX:+UseConcMarkSweepGC

-XX:+UseCMSInitiatingOccupancyOnly

-XX:CMSInitiatingOccupancyFraction=70

-XX:MaxGCPauseMillis=100  // 按业务情况来定

-XX:+PrintGCTimeStamps

-XX:+PrintGCDetails

-XX:+PrintGCDateStamps

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/9817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行驶证OCR识别接口怎么对接

行驶证OCR识别接口也叫行驶证文字识别OCR接口,指的是传入行驶证照片,精准识别静态行驶证图像上的文字信息。那么行驶证OCR识别接口怎么对接呢? 首先我们找到数脉API,然后注册账户,购买免费套餐 然后就需要公司的技术大牛把行驶证文字识别OCR…

gdb调试功能描述

gdb调试功能描述 gdb 调试:只对可执行文件进行调用,无法直接用gdb调试.c文件 1.查找命令帮助: (gdb) help data (gdb) help call -l (list) 查看载入文件(默认为10行&#xff09…

短信群发公司通道有哪些要求

短信群发公司通道有哪些要求 网络稳定性 短信群发公司的通道在进行时需要具备良好的网络稳定性。这意味着通道需要能够稳定连接到互联网,并具备高速传输能力。在网络不稳定或者传输速度慢的情况下,可能会受到影响,甚至导致失败。 高可靠性 …

linux - 主次设备号自动申请

alloc_chrdev_region 原型如下,该函数向内核申请一个空闲的主设备号。 alloc_chrdev_region(&g_aputriger_dev, 0, APUTRIGER_MAX_NUM, "aputriger0"); 第四个参数是我们使用cat /proc/devices 看到的名称 /*** alloc_chrdev_region() - register a…

持续总结中!2024年面试必问 100 道 Java基础面试题(四十)

上一篇地址:持续总结中!2024年面试必问 100 道 Java基础面试题(三十九)-CSDN博客 七十九、Java泛型中的T、R、K、V、E分别指什么? 在Java泛型中,T、R、K、V 和 E 是类型参数的常见占位符,它们用…

Babylon.js 7.0开发入门教程

Babylon.js 是一个功能强大的开源 3D 引擎,能够使用 JavaScript 渲染交互式 3D 和 2D 图形。它是为 Web 甚至 VR 创建游戏、演示、可视化和其他 3D 应用程序的绝佳选择。Babylon.js最新版本是7.0。 Babylon.js 是免费、开源和跨平台的,是 Unity 和 Unre…

LeetCode 每日一题 ---- 【1463.摘樱桃 II】

LeetCode 每日一题 ---- 【1463.摘樱桃 II】 1463.摘樱桃II方法:动态规划(递推) 1463.摘樱桃II 方法:动态规划(递推) 昨天是摘樱桃I,今天是II,与昨天的区别主要在于,今…

【进程替换】多进程程序替换原理 | 进程程序替换函数 | execlexecv | execlpexecvp

目录 多进程程序替换 多进程程序替换原理 进程程序替换函数详解 execl&execv execlp&execvp execle&execvpe execve 多进程程序替换 我们想要进程替换的同时不影响旧的进程(使用多进程版)fork创建子进程,让子进程去替换执…

2008NOIP普及组真题 4. 立体图

线上OJ: 一本通-1977:【08NOIP普及组】立体图 核心思想: 本题采用模拟方法一个一个画小方块(虽然画的是立体空间的积木,但本质还是在二维平面上画图形) 本题的难点在于: 1、如何确定二维平面画…

tengine-docker镜像制作

1.下载 wget https://tengine.taobao.org/download/tengine-3.0.0.tar.gz 或者直接下载这个包括下边两个配置文件了 https://download.csdn.net/download/cyw8998/89286114 2.编辑nginx.conf文件 #####user nobody; worker_processes 1;#error_log logs/error.log; #er…

浅析扩散模型与图像生成【应用篇】(二十三)——Imagic

23. Imagic: Text-Based Real Image Editing with Diffusion Models 该文提出一种基于文本的真实图像编辑方法,能够根据纯文本提示,实现复杂的图像编辑任务,如改变一个或多个物体的位姿和组成,并且保持其他特征不变。相比于其他文…

c语言题库之序列合并

文章目录 前言C语言题目:分析1. 合并逻辑2.图解合并逻辑 代码实现注意事项总结思考 前言 在编程中,我们经常遇到需要将两个有序序列合并为一个有序序列的问题。下面,我们就来详细探讨一下如何解决这个问题,包括输入处理、合并逻辑…

python 根据网址和关键词批量下载影像

最近用到了GLASS的LAI产品,但这个产品的文件夹分得很细,我需要的影像又有8个瓦片,一个一个点击很麻烦,于是探索了批量下载的方法 一、下载1幅 import requests import re import os import requests import re# 网页URLurl &…

深入理解Java HashSet类及其实现原理

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一…

Java中什么是多态?多态的实现原理是什么?多态在Java中的意思实现方式是什么?多态在框架设计中有什么作用应用场景?

什么是多态? 多态是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息做出响应。在 Java中,多态通常体现为子类对象可以替代父类对象的特性。这意味着你可以使用父类的引用来引用子类的对象。 多态的实现原理: 多态的…

如何在 CentOS 上安装并配置 Redis

如何在 CentOS 上安装并配置 Redis 但是太阳,他每时每刻都是夕阳也都是旭日。当他熄灭着走下山去收尽苍凉残照之际,正是他在另一面燃烧着爬上山巅散烈烈朝晖之时。 ——史铁生 环境准备 本教程将在 CentOS 7 或 CentOS 8 上进行。确保你的系统已更新到最…

Channel实现Flutter与原生平台之间的双向通信

文章目录 (一)通过MessageChannel实现Flutter与原生平台之间的双向通信Flutter端实现MessageChannel通信步骤:Android端实现MessageChannel通信步骤: (二)通过MethodChannel实现Flutter与原生平台之间的双向…

uniapp/微信小程序实现加入购物车点击添加飞到购物车动画

1、预期效果 2、实现思路 每次点击添加按钮时,往该按钮上方添加一个悬浮元素,通过位移动画将元素移到目标位置。 1. 为每个点击元素设置不同的class,才能通过uni.createSelectorQuery来获取每个元素的节点信息; 2. 添加一个与…

c++:(map和set的底层简单版本,红黑树和AVL树的基础) 二叉搜索树(BST)底层和模拟实现

文章目录 二叉搜索树的概念二叉搜索树的操作二叉搜索树的查找find 二叉搜索树的模拟实现构造节点insertfinderase(细节巨多,面试可能会考)a.叶子节点b.有一个孩子左孩子右孩子 c.有两个孩子注意: erase代码 中序遍历 二叉搜索树的应用k模型k模型模拟实现的总代码 k-value模型k-…

7-Zip命令行调用命令收集(20个)

列出压缩文件的内容: 7z l archive.7z 解压压缩文件到当前目录: 7z x archive.7z 解压压缩文件到指定目录: 7z x archive.7z -o"C:\path\to\extract" 创建新的压缩文件 (添加到archive.7z): 7z a archive.7z file_to_compress 创建包含多个文件的压缩文件: 7z a arc…