使用poi读取excel 404_Poi读取Excel引发的内存溢出

博客分析了一生产环境中由于使用POI的用户模式读取大Excel文件导致的内存泄漏问题。通过dump内存文件并使用EclipseMemoryAnalysis工具,发现POI在加载大文件时创建大量对象,占用大量内存。建议使用事件模式代替用户模式来减少内存占用,以处理大型Excel数据。本地实验验证了用户模式下读取600kb文件内存波动明显。
摘要由CSDN通过智能技术生成

前言

最近生产环境有个老项目一直内存报警,不时的还出现内存泄漏,导致需要重启服务器,已经严重影响正常服务了。

分析

1.dump内存文件

liunx使用如下命令:

./jmap -dump:format=b,file=heap.hprof pid

2.使用Eclipse Memory Analysis进行分析

1514ec55e9f5491e0068a1c354637c75.png

异常如下:

org.apache.poi.xssf.usermodel.XSSFRow.(Lorg/openxmlformats/schemas/spreadsheetml/x2006/main/CTRow;Lorg/apache/poi/xssf/usermodel/XSSFSheet;)V (XSSFRow.java:68)at org.apache.poi.xssf.usermodel.XSSFSheet.initRows(Lorg/openxmlformats/schemas/spreadsheetml/x2006/main/CTWorksheet;)V (XSSFSheet.java:157)at org.apache.poi.xssf.usermodel.XSSFSheet.read(Ljava/io/InputStream;)V (XSSFSheet.java:132)at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead()V (XSSFSheet.java:119)at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead()V (XSSFWorkbook.java:222)at org.apache.poi.POIXMLDocument.load(Lorg/apache/poi/POIXMLFactory;)V (POIXMLDocument.java:200)at org.apache.poi.xssf.usermodel.XSSFWorkbook.(Ljava/io/InputStream;)V (XSSFWorkbook.java:179)

POI在加载Excel引发了内存泄漏,中间创建了大量的对象,占用了大量的内存

3.查看上传的Excel大小

经查看发现很多Excel大小在9M的文件

4.查看代码POI读取Excel的方式

发现使用的是用户模式,这样会占用大量的内存;POI提供了2中读取Excel的模式,分别是:

用户模式:也就是poi下的usermodel有关包,它对用户友好,有统一的接口在ss包下,但是它是把整个文件读取到内存中的,

对于大量数据很容易内存溢出,所以只能用来处理相对较小量的数据;

事件模式:在poi下的eventusermodel包下,相对来说实现比较复杂,但是它处理速度快,占用内存少,可以用来处理海量的Excel数据。

经上面分析基本可以确定问题出在使用POI的用户模式去读取Excel大文件,导致内存泄漏。

本地重现

下面模拟一个600kb大小的Excel(test.xlsx),分别用两种模式读取,然后观察内存波动;

1.需要引入的库maven:

org.apache.poi poi-ooxml 3.6com.syncthemall boilerpipe 1.2.1

2.用户模式代码如下:

import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream; import org.apache.poi.ss.usermodel.Cell;import org.apache.poi.ss.usermodel.Row;import org.apache.poi.ss.usermodel.Sheet;import org.apache.poi.ss.usermodel.Workbook;import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class UserModel {  public static void main(String[] args) throws InterruptedException { try { Thread.sleep(5000); System.out.println("start read"); for (int i = 0; i < 100; i++) { try { Workbook wb = null; File file = new File("D:/test.xlsx"); InputStream fis = new FileInputStream(file); wb = new XSSFWorkbook(fis); Sheet sheet = wb.getSheetAt(0); for (Row row : sheet) { for (Cell cell : row) { System.out.println("row:" + row.getRowNum() + 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值