项目报 OutOfMemoryError 、GC overhead limit exceeded 问题排查以及解决思路实战

项目报 OutOfMemoryError、GC overhead limit exceeded 问题排查以及解决思路实战

前言:
问题现象描述:
1,生产环境有个定时任务,没有初始化告警数据【告警数据量为1000多个】
2,其他定时任务执行正常
3,查询日志到定时任务执行之前有日志打印
4,手动触发补偿告警定时任务接口报OutOfMemoryError GC overhead limit exceeded,也会报

1、现象问题排查

1.1 程序是否触发判断

1,首先定时任务之前可以正常初始化告警指标数据,说明程序可以正常执行,不会存在问题【初次判断】

1.2 JVM内存大小查看

2,会不会是内存不够用导致的结果,使用arthas工具查看内存使用情况
输入memory 返回如下信息
在这里插入图片描述

1,其中堆空间eden_space 区内存:总共462M,已使用310M
2,还剩下大概 150M左右【大概够用,只是猜想】

1.3 手动触发定时任务查看内存使用情况

1,现象是eden_space 很快达到99%,并且报GC overhead limit exceeded
在这里插入图片描述

1.4 查看定时任务代码逻辑,发现创建大量对象大概1000多个对象【在一瞬间】,代码大概如下。

1,为啥是1000多个对象,是因为有1000多个告警,要在凌晨触发定时任务生成告警指标数据
2,告警的数据,是kafka接收的,kafka监听到数据实时拉取数据,批量保存到数据库
3,告警有4大类,每个类有12个类别

未优化前逻辑

private final int batchSize = 500;
public void initKafkaAlarmInventoryTask() {
        // 待批量保存清单数据
        List<TaskAlarmInventoryEntity> batchInsertTaskInventoryList = new ArrayList<>();
        // 1.获取需要初始化的告警数据 
        // TODO: 从数据库查询 
        List<InitAlarmTaskInventoryEntity> initTaskInventoryEntities = .....
       //  initInspectionSystemMap key:为告警的类型【12大类型】 v:每个类型下面的指标集合
       initInspectionSystemMap.forEach((k, v) -> {
       		// 对每个指标进行遍历
            v.forEach(x -> {
                	// 相关业务逻辑 如果当前的告警数据已经消费到,就跳过,否则就保存消息
                	batchInsertTaskInventoryList.add(....);
                }
            });

        });
        if (CollectionUtils.isNotEmpty(batchInsertTaskInventoryList)) {
            for (int i = 0; i < batchInsertTaskInventoryList.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, batchInsertTaskInventoryList.size());
                // TODO:保存到数据库
            }
        }
    }
    }

优化后:

private final int batchSize = 500;
public void initKafkaAlarmInventoryTask() {
        // 待批量保存清单数据
        List<TaskAlarmInventoryEntity> batchInsertTaskInventoryList = new ArrayList<>();
        // 1.获取需要初始化的告警数据 
        // TODO: 从数据库查询 
        List<InitAlarmTaskInventoryEntity> initTaskInventoryEntities = .....
       //  initInspectionSystemMap key:为告警的类型【12大类型】 v:每个类型下面的指标集合
       initInspectionSystemMap.forEach((k, v) -> {
       		// 对每个指标进行遍历
            v.forEach(x -> {
                	// 相关业务逻辑 如果当前的告警数据已经消费到,就跳过,否则就保存消息
                	batchInsertTaskInventoryList.add(....);
                }
            });
        if (CollectionUtils.isNotEmpty(batchInsertTaskInventoryList)) {
            for (int i = 0; i < batchInsertTaskInventoryList.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, batchInsertTaskInventoryList.size());
                // TODO:保存到数据库
            }
        }
    }
        });
    }

4,可能是一次性初始化1000多个对象把堆内存使用完导致的这个问题,优化成根据告警指标类型分类 分成几百个类初始化,打包重新调用后,还是同样问题报错【本地执行没有问题】

1.5 使用arthas 跟踪接口执行情况

使用trace命令查看每个方法的调用时间,以及调用情况

[arthas@13362]$ trace com.xxx.xx.xx.kafka.KafkaAlarmReportConsumerClient initKafkaAlarmInventoryTask

命令大概意思是:
arthas 允许你监控指定类的方法执行过程,记录每个方法执行的时间、调用链等详细信息。
com.xxx.xx.xx.kafka.KafkaAlarmReportConsumerClient:这是目标类的完全限定名,表示 KafkaAlarmReportConsumerClient类。
initKafkaAlarmInventoryTask:这是你要追踪的方法名。Arthas 将监控该方法的执行,并返回详细的执行信息。

返回如下消息:

`---[18808.94593ms] com.xx.xxx.platform.kafka.KafkaAlarmReportConsumerClient $$EnhancerBySpringCGLIB$\$4ead41fc:initKafkaAlarmInventoryTask() [throws Exception]
    +---[100.00% 18808.534277ms ] org.springframework.cglib.proxy.MethodInterceptor:intercept() [throws Exception]
    |   `---[99.93% 18794.767357ms ] com.xx.xxx.xx.kafka.KafkaReportConsumerClient:initKafkaAlarmTask() [throws Exception]
    |       +---[0.00% 0.032337ms ] com.xx.xx.platform.entity.dao.TaskInventoryDao:builder() #826
    |       +---[0.00% 0.220948ms ] com.xxx.major.common.utils.DateUtils:getStartDate() #826
    |       +---[0.00% 0.014243ms ] com.xx.xx.platform.xxx.xx.TaskInventoryDao$TaskInventoryDaoBuilder:synStartDate() #826
    |       +---[0.00% 0.224577ms ] com.xxx.xxx.common.utils.DateUtils:getEndDate() #826
    |       +---[0.00% 0.010579ms ] com.xxx.major.xxx.entity.xxx.TaskInventoryDao$TaskInventoryDaoBuilder:synEndDate() #826
    |       +---[0.00% 0.009368ms ] com.xx.major.xxx.entity.xxx.TaskInventoryDao$TaskInventoryDaoBuilder:build() #826
    |       +---[0.21% 38.643543ms ] com.xxx.major.xxx.service.TaskInventoryService:queryTaskInventoryByTaskInventoryDao() #825
    |       +---[0.60% 112.059449ms ] com.xxx.major.platform.service.InitTaskInventoryService:queryAllInitTaskInventory() #836
    |       +---[0.00% 0.286756ms ] com.xxx.major.common.utils.DateUtils:getEndDate() #842
    |       +---[0.17% 32.261925ms ] com.xxxx.major.platform.service.TaskInventoryService:queryTaskInventoryByParam() #842
    `---throw:java.lang.OutOfMemoryError #-1 [GC overhead limit exceeded]

返回的大概意思是:

2.3.1. 方法调用路径:
com.xxx.major.platform.kafka.KafkaAlarmReportConsumerClient KaTeX parse error: Can't use function '$' in math mode at position 22: …erBySpringCGLIB$̲\$4ead41fc:init…EnhancerBySpringCGLIB$$4ead41fc)是由 Spring 的 CGLIB 动态代理生成的类,initKafkaAlarmTask 是该方法。它的执行时间是 18808.94593ms(约 18.8 秒)。

org.springframework.cglib.proxy.MethodInterceptor:intercept() [throws Exception]:
这表示 Spring AOP 拦截器的执行,它拦截了对 initKafkaAlarmTask 的调用,并花费了 18808.534277ms。

com.xxx.major.platform.kafka.KafkaReportConsumerClient:initKafkaAlarmTask() [throws Exception]:
这表示实际的业务逻辑方法 initKafkaAlarmTask 被执行,并且占用了 18794.767357ms,几乎占用了整个时间。

2.3.2. 方法调用过程中的内部调用:
接下来是对 initKafkaAlarmTask 方法内部的其他方法的详细追踪:

TaskAlarmInventoryDao.builder():用时 0.032337ms。
DateUtils.getStartDate():用时 0.220948ms。
TaskAlarmInventoryDao T a s k A l a r m I n v e n t o r y D a o . s y n S t a r t D a t e ( ) :用时 0.014243 m s 。 D a t e U t i l s . g e t E n d D a t e ( ) :用时 0.224577 m s 。 T a s k A l a r m I n v e n t o r y D a o TaskAlarmInventoryDao.synStartDate():用时 0.014243ms。 DateUtils.getEndDate():用时 0.224577ms。 TaskAlarmInventoryDao TaskAlarmInventoryDao.synStartDate():用时0.014243msDateUtils.getEndDate():用时0.224577msTaskAlarmInventoryDaoTaskAlarmInventoryDao.synEndDate():用时 0.010579ms。
TaskAlarmInventoryDao$TaskAlarmInventoryDao.build():用时 0.009368ms。
TaskAlarmInventoryService.queryTaskIAlarmnventoryByTaskInventoryDao():用时 38.643543ms。
InitTaskAlarmInventoryService.queryAllAlarmInitTaskInventory():用时 112.059449ms。
TaskAlarmInventoryService.queryTaskAlarmInventoryByParam():用时 32.261925ms。

简短说,异常信息是:
最后,输出中显示了一个 java.lang.OutOfMemoryError 异常,指示发生了 GC overhead limit exceeded 错误。这表示在执行过程中,JVM 因垃圾回收器(GC)花费了过多的时间,但并未有效释放内存,导致内存溢出异常。

throw:java.lang.OutOfMemoryError #-1 [GC overhead limit exceeded] 表明 JVM 由于 GC 限制,无法回收足够的内存,最终触发了 OutOfMemoryError。

1.6 查看JVM参数配置:

arthas 输入 jvm,返回如下内容 生成环境是1g,测试环境是512M这里只是做个已有JVM参数样例
在这里插入图片描述
1,问题一:
永久代和 Metaspace 配置:

由于 Java 8 及以后版本中已经没有永久代(PermGen),而是使用 Metaspace,因此 -XX:PermSize 和 -XX:MaxPermSize 参数已经不再生效。
建议: 移除这些不再有效的参数,使用 Metaspace 相关的参数,如 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize,例如

-XX:MetaspaceSize=128M
-XX:MaxMetaspaceSize=512M

2,问题二:
当发生 OutOfMemoryError(OOM)错误时,JVM(Java虚拟机)会生成一个堆转储文件(heap dump)。这个文件包含了JVM内存堆的快照,包含了Java对象的详细信息,帮助开发者和运维人员分析和定位内存泄漏或内存不足的原因。分析堆转储文件是解决这类问题的一个重要步骤。

  1. 堆转储文件的生成
    当出现 OutOfMemoryError 时,JVM会通过以下方式生成堆转储文件:

使用 -XX:+HeapDumpOnOutOfMemoryError 参数自动在OOM发生时生成堆转储。
堆转储文件通常会保存到指定的文件路径,如:-XX:HeapDumpPath=/path/to/dump.hprof。

查看当前文件夹存在xxx.hprof快照信息

在这里插入图片描述

1.7 将堆转储文件copy出来,用jdk自带的 java VisualVm分析

1,双击执行

在这里插入图片描述

2,文件 装入 快照信息

在这里插入图片描述

3,文件类型选择并装入

在这里插入图片描述

4,注意文件类型,是否选错
5,点击异常线程选择,找到问题所在

在这里插入图片描述

6,问题定位

找到问题的代码位置
在这里插入图片描述

7,根据问题找到的代码位置

在这里插入图片描述

8,计算类所占内存的大小

这里可以看到最大的有char[]实例大小和总大小,总实例的个数是740890,总大小是306,889,752单位是B,换成MB为,306,889,752➗1024➗1024≈292.67287445068359375≈293MB,这个跟启动JVM参数设置最大堆内存设置-Xmx512M 和这个相差不大**(-Xmx=512m虽然堆分配是512m,但是JVM会拓展)**在这里插入图片描述
在这里插入图片描述
如果没有显示引用下面的数据,记得把这个点开
在这里插入图片描述

2、问题跟踪解决

问题一:
1,定时任务触发,会很一次性触发1000多个对象,
解决方案:
拆分成根据告警指标类型进行分开,仍然是批处理,一次性创建的对象最大为500个左右
问题二:
根据上面排查原因点7,发现是kafka消费者拉取数据量为500而且是多线程导致,造成数据量庞大,内存OOM,
解决方案:
1、把多线程去掉,或者最大线程数改为单个,每次拉取500个数据,
2、查看当前服务器内存使用情况
free -h
返回如下,mem的free还剩1.2G,加到当前服务JVM参数即可
在这里插入图片描述
并调整-Xms堆的大小 改为512m+1024m

3、遇到的问题

1,arthas 服务器拉取不到,需要外网下载好arthas,copy到服务器
电脑盘创建文件夹执行如下命令即可
参考官网网址:https://arthas.aliyun.com/doc/install-detail.html

-- 下载arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
-- 执行脚本
java -jar arthas-boot.jar

2,服务器hprof快照信息,导出win环境,可能权限不对,要将hprof快照信息设置成所有人都可执行的权限

-- 修改为所有用户都可以执行
chmod a+rwx java_pid25304.hprof

在这里插入图片描述

3,JVM已有参数配置失效,JVM调优参数下一期讲解 待完成…

本次OOM,GC问题做个记录分享给大家,生产项目难免有些没有表达合理CV清楚,欢迎指出来,我这边改好更新后再发上去
喜欢我的文章记得点个在看,或者点赞,持续更新中ing…

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

xinput1_3.dll放在哪里?当xinput1_3.dll丢失时的应对策略:详细解决方法汇总

在计算机系统的运行过程中&#xff0c;我们偶尔会遇到一些令人困扰的问题&#xff0c;其中xinput1_3.dll文件丢失就是较为常见的一种情况。这个看似不起眼的动态链接库文件&#xff0c;实则在许多软件和游戏的正常运行中发挥着至关重要的作用。一旦它丢失&#xff0c;可能会导致…

【Compose multiplatform教程12】【组件】Box组件

查看全部组件文章浏览阅读493次&#xff0c;点赞17次&#xff0c;收藏11次。alignment。https://blog.csdn.net/b275518834/article/details/144751353 Box 功能说明&#xff1a;简单的布局组件&#xff0c;可容纳其他组件&#xff0c;并依据alignment属性精确指定内部组件的对…

MySql:复合查询

✨✨作者主页&#xff1a;嶔某✨✨ ✨✨所属专栏&#xff1a;MySql✨ 准备工作&#xff0c;创建一个雇员信息表&#xff08;来自oracle 9i的经典测试表&#xff09; EMP员工表DEPT部门表SALGRADE工资等级表 多表查询 显示雇员名&#xff0c;雇员工资以及所在部门的名字 因为…

从零创建一个 Django 项目

1. 准备环境 在开始之前&#xff0c;确保你的开发环境满足以下要求&#xff1a; 安装了 Python (推荐 3.8 或更高版本)。安装 pip 包管理工具。如果要使用 MySQL 或 PostgreSQL&#xff0c;确保对应的数据库已安装。 创建虚拟环境 在项目目录中创建并激活虚拟环境&#xff…

基于PREEvision的UML设计

众所周知&#xff0c;PREEvision是一款强大的电子电气架构协同开发及管理软件&#xff0c;可以很好地帮助架构工程师完成架构开发工作&#xff0c;其功能包括需求管理、定义功能逻辑、系统软件开发、网络设计、线束设计及整体工程的产品线管理和变形管理等。随着工程师们越来越…

Azure Function 解决跨域问题

这边前端call本地部署的azure function出现了跨域问题&#xff0c;搜索一下解决方案 直接修改local.setting.json&#xff0c;在其中添加CORS配置为通配符”*”&#xff0c;就行了 local.settings.json {"IsEncrypted": false,"Values": {"PYTHON_E…

Ubuntu离线安装Docker容器

前言 使用安装的工具snap安装在沙箱中&#xff0c;并且该沙箱之外的权限有限。docker无法从其隔离的沙箱环境访问外部文件系统。 目录 前言准备环境卸载已安装的Docker环境快照安装的Dockerapt删除Docker 安装docker-compose下载执行文件将文件移到 /usr/local/bin赋予执行权限…

CMake 构建项目并整理头文件和库文件

本文将介绍如何使用 CMake 构建项目、编译生成库文件&#xff0c;并将头文件和库文件整理到统一的目录中以便在其他项目中使用。 1. 项目结构 假设我们正在构建一个名为 rttr 的开源库&#xff0c;初始的项目结构如下&#xff1a; D:\WorkCode\Demo\rttr-master\|- src\ …

JAVA HTTP压缩数据

/*** 压缩数据包** param code* param data* param resp* throws IOException*/protected void writeZipResult(int code, Object data, HttpServletResponse resp) throws IOException {resp.setHeader("Content-Encoding", "gzip");// write到客户端resp…

公路边坡安全监测中智能化+定制化+全面守护的应用方案

面对公路边坡的安全挑战&#xff0c;我们如何精准施策&#xff0c;有效应对风险&#xff1f;特别是在强降雨等极端天气下&#xff0c;如何防范滑坡、崩塌、路面塌陷等灾害&#xff0c;确保行车安全&#xff1f;国信华源公路边坡安全监测解决方案&#xff0c;以智能化、定制化为…

uniapp 微信小程序 数据空白展示组件

效果图 html <template><view class"nodata"><view class""><image class"nodataimg":src"$publicfun.locaAndHttp()?localUrl:$publicfun.httpUrlImg(httUrl)"mode"aspectFit"></image>&l…

41.欠采样技术下变频不能用与跨两个nyquist的情况下

当接收到的信号位于同一nyquist区间时&#xff0c;信号被成功的折叠到了第一Nyquist区间中。 当接收信号位于两个或多个采样区间时&#xff0c;最后多个区间的信号都会被折叠到第一Nyquist区间中造成信号的重叠。

AI新书推荐:深度学习和大模型原理与实践(清华社)

本书简介 在这个信息爆炸、技术革新日新月异的时代&#xff0c;深度学习作为人工智能领域的重要分支&#xff0c;正引领着新一轮的技术革命。《深度学习和大模型原理与实践》一书&#xff0c;旨在为读者提供深度学习及其大模型技术的全面知识和实践应用的指南。 本书特色在于…

Vue项目中env文件的作用和配置

在实际项目的开发中&#xff0c;我们一般会经历项目的开发阶段、测试阶段和最终上线阶段&#xff0c;每一个阶段对于项目代码的要求可能都不尽相同&#xff0c;那么我们如何能够游刃有余的在不同阶段下使我们的项目呈现不同的效果&#xff0c;使用不同的功能呢&#xff1f;这里…

Ubuntu 22.04.5 修改IP

Ubuntu22.04.5使用的是netplan管理网络&#xff0c;因此需要在文件夹/etc/netplan下的01-network-manager-all.yaml中修改&#xff0c;需要权限&#xff0c;使用sudo vim或者其他编辑器&#xff0c;修改后的内容如下&#xff1a; # Let NetworkManager manage all devices on …

NeeView(图像查看器) v42.4

NeeView是一款功能强大的图像查看器&#xff0c;它为用户提供了一种独特的方式&#xff0c;可以像翻阅书籍一样轻松地浏览文件夹中的图像。这款软件支持多种标准的兼容图像格式&#xff0c;包括bmp、jpg、gif、tiff、png、ico、svg以及WIC兼容图像&#xff0c;这意味着用户可以…

动态规划子序列问题系列一>等差序列划分II

题目&#xff1a; 解析&#xff1a; 1.状态表示&#xff1a; 2.状态转移方程&#xff1a; 这里注意有个优化 3.初始化&#xff1a; 4.填表顺序&#xff1a; 5.返回值&#xff1a; 返回dp表总和 代码&#xff1a; public int numberOfArithmeticSlices(int[] nums) {in…

代码随想录Day52 101. 孤岛的总面积,102. 沉没孤岛,103. 水流问题,104.建造最大岛屿。

1.孤岛的总面积 卡码网&#xff1a;101. 孤岛的总面积(opens new window) 题目描述 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域&#xff0c;且完全被水域单元格…

【高阶数据结构】红黑树模拟实现map、set

红黑树模拟实现map、set 1.源码及框架分析2.模拟实现map和set1.支持 insert 的实现2.支持 iterator 的实现3.map支持 operator [] 的实现 3.总代码1.RBTree.h2.Myset.h3.Mymap.h4.Test.cpp 1.源码及框架分析 SGI-STL30版本源代码&#xff0c;map和set的源代码在map/set/stl_ma…

邮箱手机号脱敏

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 输入框的脱敏&#xff0c;当输入的时候显示正常&#xff0c;失去焦点部分显示**** 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 脱敏可以封装 一下成为一个方法&#xff0c;挂…