记一次使用easyexcel导入excel导致cpu跑满的问题
记一次poi导入excel引起cpu跑满的问题
生产应用机器配置:8C 16G
周日突然收到告警,cpu持续15分钟空闲时间小于10%,赶紧联系运维要日志,通过分析dump_high_cpu
1 2 3 4 5 6 7 8 9 10 11 | PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 28830 jbossuse 20 0 12 .9g 6 .9g 27m R 100.9 44.6 16 : 12.49 java 29157 jbossuse 20 0 12 .9g 6 .9g 27m R 100.9 44.6 11 : 43.56 java 29991 jbossuse 20 0 12 .9g 6 .9g 27m R 100.9 44.6 14 : 31.26 java 30187 jbossuse 20 0 12 .9g 6 .9g 27m R 100.9 44.6 14 : 06.83 java 30408 jbossuse 20 0 12 .9g 6 .9g 27m R 100.9 44.6 13 : 02.85 java 30599 jbossuse 20 0 12 .9g 6 .9g 27m R 100.9 44.6 12 : 44.31 java 28840 jbossuse 20 0 12 .9g 6 .9g 27m R 99.1 44.6 15 : 44.46 java 29165 jbossuse 20 0 12 .9g 6 .9g 27m R 95.5 44.6 15 : 37.87 java 27522 jbossuse 20 0 12 .9g 6 .9g 27m S 0.0 44.6 0 : 00.00 java 27523 jbossuse 20 0 12 .9g 6 .9g 27m S 0.0 44.6 0 : 00.68 java |
看出来,有8个线程跑到100%.通过pid去寻找对应java core 里的线程,发现这个8个线程都是进行同一个操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | "default task-17" prio= 10 tid= 0x00007ff15802f000 nid= 0x71ed runnable [ 0x00007ff1f10ac000 ] java.lang.Thread.State: RUNNABLE at org.apache.xmlbeans.impl.store.Locale.count(Locale.java: 2049 ) at org.apache.xmlbeans.impl.store.Xobj.count_elements(Xobj.java: 2050 ) at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTColsImpl.sizeOfColArray(Unknown Source) - locked < 0x00000006e8d5c800 > (a org.apache.xmlbeans.impl.store.Locale) at org.apache.poi.xssf.usermodel.helpers.ColumnHelper.addCleanColIntoCols(ColumnHelper.java: 115 ) at org.apache.poi.xssf.usermodel.helpers.ColumnHelper.cleanColumns(ColumnHelper.java: 56 ) at org.apache.poi.xssf.usermodel.helpers.ColumnHelper.<init>(ColumnHelper.java: 43 ) at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java: 144 ) at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java: 130 ) at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java: 286 ) at org.apache.poi.POIXMLDocument.load(POIXMLDocument.java: 159 ) at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java: 186 ) at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java: 73 ) |
定位到占满cpu的操作,是用poi导入execl ,找到代码处,发现已经限制了导入的excel的大小为1MB,但是没有限制导入频率,这样的话,用户短时间内可以频繁导入数据到系统.
那么问题来了,频繁导入1MB的excel为什么会导致cpu跑满?拉取了gc日志发现jvm在频繁的ygc,平均几秒就发生一次.并且在分析问题的这段时间,cpu仍然没有下降,占用cpu高的线程仍然在持续,会不会是这几个线程在创建大量对象,导致ygc频繁回收,而且回收的年轻代空间仍然不满足线程的需要,进而引发cpu跑满?
这是一个很合理的猜测,但是需要事实来证明,在确认这台机器无法自行恢复之后,联系运维先拉取了dump文件,然后重启机器.
经过了漫长的等待,终于到手了dump文件,分析dump文件后发现,有大量的char[] 和list对象在生成.这个和猜测以及本身定位到的poi代码处实现一致.
最终问题定位后的描述如下:
在某个业务场景,报表导入没有频次限制,导致用户可以重复高频次的导入excel到系统,导致系统在用poi解析时,生成了大量的对象,并且poi在最终汇总对象时加了锁,jvm年轻代在回收多次之后仍然不满足线程所需,引发锁自旋,导致cpu跑满.
问题定位出来了,但是还有一点疑惑,为什么1MB的对象在生产poi对象时,会占用更多的内存呢?
原来,poi读取excel有两种方式,一种是用户模式,另外一种是事件模式。用户有封装好的方法,使用简单,但是会创建非常多的对象,耗内存,后者用来读取excel,但不用把整个excel加载到内存,减少了至少10倍的内存使用
最终的疑惑也解决了,项目中使用的方式都是用户模式,这才导致了大量内存的消耗,接下来该想想如何把项目中的读取模式切换成事件模式了,以防其他地方再次出现今天这样的问题。
出处:http://www.cnblogs.com/lingyejun/
若本文如对您有帮助,不妨点击一下右下角的【推荐】。
如果您喜欢或希望看到更多我的文章,可扫描二维码关注我的微信公众号《翎野君》。
转载文章请务必保留出处和署名,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2023-06-03 idea自动编译失效,每次修改代码都需要重新clean install
2023-06-03 Python写入文件报错‘gbk’ codec can’t encode character的解决办法