记一次EasyExcel的错误使用导致的频繁FullGC

记一次EasyExcel的错误使用导致的频繁FullGC

      • 一、背景描述
      • 二、场景复现
      • 三、原因分析
      • 四、解决方案
      • 五、思考复盘

一、背景描述

繁忙的校招结束了,美好的大学四年也结束了,作者也有10个月没有更新了。拿到心仪的offer之后也开始了苦B的打工生活。

最近接到了这样的一个需求:从大量Excel文件中清洗出来关键信息,文件数量很多,数据量也很大。

早就听说EasyExcel是处理Excel的利器,性能极高的同时还不会出现内存溢出,作者想都没想就开始用了起来,于是就有了今天这篇文章。。。。

二、场景复现

参照GPT以及一些文档还有以前的一点点使用经验,作者写了这样一段代码。

@Component
public class EasyExcelUtil {// 这里开了32个线程@Async("excelExecutor")public void test(String fileName){ExcelReaderBuilder read = EasyExcel.read(fileName);List<Object> objects = read.doReadAllSync();// 其他处理逻辑}
}

观察了一会日志,发现运行的还挺正常,作者就心满意足的去写文档了,悲剧的是写完文档回来发现,GC日志上面疯狂的FullGC,文件也只处理了一千个左右,当时的心情是极其复杂的,于是就开始了漫长的排查。

三、原因分析

首先观察日志,这时候有些文件其实还是被处理了的,频繁的FullGC日志中有一些年轻代是被正常回收了的,但是老年代已经满了,且无论怎么回收,都不会被回收掉,这时候其实就可以想到一种可能性是有一些不会被FullGC回收的大对象存在。于是我去dump了堆内存图,老年代的分布大概是这样的:

在这里插入图片描述

其中SyncReadListener的对象躲过了所有的FullGC且没有GC Root,猜测一定是SyncReadListener这个类出现了什么问题,我们先看doReadAllSync()这个方法的源码

在这里插入图片描述

可以看到是先注册了SyncReadListener这个监听器,然后构造了一个excelReader对象,通过excelReader对excel进行读取,那为什么SyncReadListener会出现这么多大对象呢,我们看看源码。

在这里插入图片描述

SyncReadListener可以将某些数据一条条的塞进去,这里我们合理推测其实就是我们读取到的数据被传递给了监听器,但是为什么没有被垃圾回收掉呢?推测问题应该就出现在了ExcelReader这个类。

首先是常量定义和一些读取的方法。

在这里插入图片描述

接下来这部分内容就有意思了,也是问题所在。

在这里插入图片描述

这个类重写了finalize方法,调用了一次finish()方法,而刚才的代码中调用的逻辑是这样的

excelReader.readAll();
excelReader.finish();

具体的逻辑就不细看了,语义上的描述大概是读取所有的内容,然后手动关闭。

这时候就真相大白了,结合我们的代码中又添加了@Async注解,场景发生的原因大概是:

多个线程同时读取到了超大文件,导致在excelReader.readAll()过程中老年代被打满,老年代已经没有空间去读取这几个超大文件中的内容了,且由于ExcelReader重写了finalize()方法,并不会进入到GC队列,这就会导致老年代的占用一直是接近100%,不断的触发FullGC,而那些使用年轻代就能进行读取的小文件就可以正常的进行数据解析,随后被GC掉。

四、解决方案

学习了官方文档后,发现作者的场景应该使用这部分逻辑,即继承AnalysisEventListener,重写invoke方法,doAfterAllAnalysed()方法,最关键的是定义一个没读取一部分数据就释放空间的List,这样可以实现读取一部分内容后就释放内存,不会出现读取超大文件导致大对象无法回收的问题,也是这个工具类的正确使用方法。

在这里插入图片描述

五、思考复盘

  1. 选择某个工具类实现功能的时候一定要充分阅读文档,找到自己需要的能力
  2. 学习JVM,这会让好多排查过程变得非常轻松
  3. 养成阅读源码的习惯,快速定位生产中的问题
  4. 学习设计模式,哪怕自己的屎山没机会通过设计模式重构,也能提高自己阅读优秀开源组件实现逻辑的能力

最后感慨一下:用EasyExcel这个组件好长时间了,都没有去探索他的实现逻辑,而且最开始使用EasyExcel真的是觉得他用起来比POI更加的Easy,根本不了解他可以解决内存溢出的问题,更是忽略掉了这个组件的更加牛逼的用途,自己的成长空间还是很大啊。。。

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

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

相关文章

Python海量数据处理脚本大集合:pyWhat

pyWhat&#xff1a;精简海联数据&#xff0c;直达数据弱点要害- 精选真开源&#xff0c;释放新价值。 概览 pyWhat是Github社区上一款比较实用的开源Python脚本工具。它能够快速提取信息中的 IP 地址、邮箱、信用卡、数字货币钱包地址、YouTube 视频等内容。当你遇到了一串莫名…

【PYG】Planetoid中边存储的格式,为什么打印前十条边用edge_index[:, :10]

edge_index 是 PyTorch Geometric 中常用的表示图边的张量。它通常是一个形状为 [2, num_edges] 的二维张量&#xff0c;其中 num_edges 表示图中边的数量。每一列表示一条边&#xff0c;包含两个节点的索引。 实际上这是COO存储格式&#xff0c;官方文档里也有写&#xff0c;…

上位机图像处理和嵌入式模块部署(mcu 项目1:固件编写)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 说完了上位机的开发&#xff0c;接下来就是固件的开发。前面我们说过&#xff0c;目前使用的开发板是极海apm32f103的开发板。它自身包含了iap示例…

一些迷你型信息系统

只有一个表&#xff0c;比较简单易用&#xff1b; 1 博物馆信息查询系统 信息录入&#xff0c;浏览&#xff0c;添加&#xff0c;更新&#xff0c;删除&#xff1b; 下载&#xff0c; https://download.csdn.net/download/bcbobo21cn/89505217

中国网络安全审查认证和市场监管大数据中心数据合规官CCRC-DCO

关于CCRC-DCO证书的颁发机构&#xff0c;它是由中国网络安全审查认证与市场监管大数据中心&#xff08;简称CCRC&#xff09;负责。 该中心在2006年得到中央机构编制委员会办公室的批准成立&#xff0c;隶属于国家市场监督管理总局&#xff0c;是其直辖的事业单位。 依据《网络…

计算机的错误计算(十八)

摘要 计算机的错误计算&#xff08;四&#xff09;指出一元二次方程的计算精度问题。本节给出其一种解决方案。 计算机的错误计算&#xff08;四&#xff09;与&#xff08;十七&#xff09;分别指出一元二次方程的求解是具有挑战性的难题&#xff0c;其出错原因是因为相减相消…

YOLOv10(7):YOLOv10训练(以训练VOC数据集为例)

YOLOv10&#xff08;1&#xff09;&#xff1a;初探&#xff0c;训练自己的数据_yolov10 训练-CSDN博客 YOLOv10&#xff08;2&#xff09;&#xff1a;网络结构及其检测模型代码部分阅读_yolov10网络结构图-CSDN博客 YOLOv10&#xff08;4&#xff09;&#xff1a;损失&…

【Linux】初识操作系统

一、冯•诺依曼体系结构 在学习操作系统之前&#xff0c;我们先来认识一下冯•诺依曼体系结构&#xff0c;我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 截至目前&#xff0c;我们所认识的计算机&am…

神经网络训练(一):基于残差连接的图片分类网络(ResNet18)

目录 一、简介:二、图片分类网络1.记载训练数据(torch自带的cifa10数据集)2.数据增强3.模型构建4.模型训练三、完整源码及文档一、简介: 基于残差连接的图片分类网络,本网络使用ResNet18作为基础模块,根据cifa10的特点进行改进网络,使用交叉熵损失函数和SGD优化器。本网…

使用pyqt5编写一个七彩时钟

使用pyqt5编写一个七彩时钟 效果代码解析定义 RainbowClockWindow 类初始化用户界面显示时间方法 完整代码 在这篇博客中&#xff0c;我们将使用 PyQt5 创建一个简单的七彩数字时钟。 效果 代码解析 定义 RainbowClockWindow 类 class RainbowClockWindow(QMainWindow):def _…

【TB作品】温湿度监控系统设计,ATMEGA16单片机,Proteus仿真

题2:温湿度监控系统设计 功能要求: 1)开机显示时间(小时、分)、时分可修改; 2)用两个滑动变阻器分别模拟温度传感器(测量范 围0-100度)与湿度传感器(0-100%),通过按键 可以在数码管切换显示当前温度值、湿度值; 3)当温度低于20度时,红灯长亮; 4)当湿度高于70%时,黄灯长亮; 5)当…

安卓实现微信聊天气泡

一搜没一个能用的&#xff0c;我来&#xff1a; 布局文件&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xml…

Tech Talk:智能电视eMMC存储的五问五答

智能电视作为搭载操作系统的综合影音载体&#xff0c;以稳步扩大的市场规模走入越来越多的家庭&#xff0c;成为人们生活娱乐的重要组成部分。存储部件是智能电视不可或缺的组成部分&#xff0c;用于保存操作系统、应用程序、多媒体文件和用户数据等信息。智能电视使用eMMC作为…

vue3中使用Antv G6渲染树形结构并支持节点增删改

写在前面 在一些管理系统中&#xff0c;会对组织架构、级联数据等做一些管理&#xff0c;你会怎么实现呢&#xff1f;在经过调研很多插件之后决定使用 Antv G6 实现&#xff0c;文档也比较清晰&#xff0c;看看怎么实现吧&#xff0c;先来看看效果图。点击在线体验 实现的功能…

受限玻尔兹曼机浅析

受限玻尔兹曼机&#xff08;Restricted Boltzmann Machine&#xff0c;简称RBM&#xff09;是一种特殊的随机生成神经网络&#xff0c;能够学习并发现数据的复杂规则分布。以下是关于受限玻尔兹曼机算法的详细介绍&#xff1a; ⭐️ 定义与起源 定义&#xff1a; 受限玻尔兹…

深入剖析Tomcat(十四) Server、Service 组件:如何启停Tomcat服务?

通过前面文章的学习&#xff0c;我们已经了解了连接器&#xff0c;四大容器是如何配合工作的&#xff0c;在源码中提供的示例也都是“一个连接器”“一个顶层容器”的结构。并且启动方式是分别启动连接器和容器&#xff0c;类似下面代码 connector.setContainer(engine); try …

小程序的运行机制、更新机制、生命周期介绍保姆级教程全解

一、小程序运行机制 1. 小程序冷启动 小程序启动可以分为两种情况&#xff0c;一种是冷启动&#xff0c;一种是热启动- 冷启动&#xff1a;如果用户首次打开&#xff0c;或小程序销毁后被用户再次打开&#xff0c;此时小程序需要重新加载启动- 热启动&#xff1a;如果用户已经打…

HSP_12章 Python面向对象编程oop_多态

文章目录 P128 多态问题的引出P129 多态细节和使用1. 多态介绍&特别说明2. 多态的好处3. 特别说明: Python多态的特点4. 使用多态的机制来解决主人喂食物的问题 P128 多态问题的引出 先看一个问题 # 说明: 先试用传统的方式完成 class Food:name Nonedef __init__(self,…

4.Android逆向协议-详解二次打包失败解决方案

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;微尘网校 上一个内容&#xff1a;3.Android逆向协议-APP反反编译及回编译 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.…

#笔记# 写给自己用的小爬虫

最近完成了一个文旅行业信息聚合的小应用&#xff0c;实现仅从一个入口了解全行业的信息动态&#xff0c;不用一个一个翻看各网站&#xff0c;节省了不少检索时间。 一、基本思路 明确数据来源。基于前述目标&#xff0c;确定数据源为文化和旅游部管理部门官网&#xff0c;比…