POI大量数据读取内存溢出分析及解决方案
点击关注公众号,实用技术文章及时了解
来源:blog.csdn.net/liangjf85/article/
details/84914798
在使用POI进行excel操作时,当数据量较大时经常会产生内存溢出异常。下面我们通过分析如何解决该问题
一、POI结构图
二、内存溢出问题
在项目中遇到二十万行数据要写入到excel中时会内存溢出,一般方法是调大tomcat的内存,但是调到2048M还是会内存溢出报错。因此我们分析其原因。
我们通过分析其源码,得出其实现步骤为通过InputStream一行行读取到TreeMap类型的HSSFRow结构体中,因此当数据量大时就会造成内存溢出。
public HSSFWorkbook(DirectoryNode directory, boolean preserveNodes)throws IOException{super(directory);String workbookName = getWorkbookDirEntryName(directory);this.preserveNodes = preserveNodes;// If we're not preserving nodes, don't track the// POIFS any moreif(! preserveNodes) {clearDirectory();}_sheets = new ArrayList<HSSFSheet>(INITIAL_CAPACITY);names = new ArrayList<HSSFName>(INITIAL_CAPACITY);// Grab the data from the workbook stream, however// it happens to be spelled.InputStream stream = directory.createDocumentInputStream(workbookName);List<Record> records = RecordFactory.createRecords(stream);workbook = InternalWorkbook.createWorkbook(records);setPropertiesFromWorkbook(workbook);int recOffset = workbook.getNumRecords();// convert all LabelRecord records to LabelSSTRecordconvertLabelRecords(records, recOffset);RecordStream rs = new RecordStream(records, recOffset);while (rs.hasNext()) {try {InternalSheet sheet = InternalSheet.createSheet(rs);_sheets.add(new HSSFSheet(this, sheet));} catch (UnsupportedBOFType eb) {// Hopefully there's a supported one after this!log.log(POILogger.WARN, "Unsupported BOF found of type " + eb.getType());}}for (int i = 0 ; i < workbook.getNumNames() ; ++i){NameRecord nameRecord = workbook.getNameRecord(i);HSSFName name = new HSSFName(this, nameRecord, workbook.getNameCommentRecord(nameRecord));names.add(name);}}
/*** add a row to the sheet** @param addLow whether to add the row to the low level model - false if its already there*/private void addRow(HSSFRow row, boolean addLow) {_rows.put(Integer.valueOf(row.getRowNum()), row);if (addLow) {_sheet.addRow(row.getRowRecord());}boolean firstRow = _rows.size() == 1;if (row.getRowNum() > getLastRowNum() || firstRow) {_lastrow = row.getRowNum();}if (row.getRowNum() < getFirstRowNum() || firstRow) {_firstrow = row.getRowNum();}}
excel数据行读取到内存的存储结构如下:
三、解决方案
poi官网给了一种大批量数据写入的方法,使用SXXFWorkbook类进行大批量写入操作解决了这个问题,可以监控该样例,我们会发现整体内存呈现锯齿状,能够及时回收,内存相对比较平稳。
package org.bird.poi;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;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.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.junit.Assert;public class XSSFWriter {private static SXSSFWorkbook wb;public static void main(String[] args) throws IOException {wb = new SXSSFWorkbook(10000);Sheet sh = wb.createSheet(); for(int rownum = 0; rownum < 100000; rownum++){ Row row = sh.createRow(rownum); for(int cellnum = 0; cellnum < 10; cellnum++){ Cell cell = row.createCell(cellnum); String address = new CellReference(cell).formatAsString(); cell.setCellValue(address); } } // Rows with rownum < 900 are flushed and not accessible for(int rownum = 0; rownum < 90000; rownum++){ Assert.assertNull(sh.getRow(rownum)); } // ther last 100 rows are still in memory for(int rownum = 90000; rownum < 100000; rownum++){ Assert.assertNotNull(sh.getRow(rownum)); } URL url = XSSFWriter.class.getClassLoader().getResource("");FileOutputStream out = new FileOutputStream(url.getPath() + File.separator + "wirter.xlsx"); wb.write(out); out.close(); // dispose of temporary files backing this workbook on disk wb.dispose(); }
}
推荐
主流Java进阶技术(学习资料分享)
Java面试题宝典
加入Spring技术开发社区
PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!
POI大量数据读取内存溢出分析及解决方案相关推荐
- Java 中如何解决 POI 读写 excel 几万行数据时内存溢出的问题?(附源码)
>>号外:关注"Java精选"公众号,菜单栏->聚合->干货分享,回复关键词领取视频资料.开源项目. 1. Excel2003与Excel2007 两个版本 ...
- java内存溢出分析工具:jmap使用实战
java内存溢出分析工具:jmap使用实战 在一次解决系统tomcat老是内存撑到头,然后崩溃的问题时,使用到了jmap. 1 使用命令 在环境是linux+jdk1.5以上,这个工具是自带的,路 ...
- 内存溢出分析之工具篇
内存溢出分析之工具篇 转载于:https://www.cnblogs.com/lwmp/p/9850446.html
- JVM 调优实战--jmap的使用以及内存溢出分析
目录 jmap的使用以及内存溢出分析 查看内存使用情况 查看内存中对象数量及大小 将内存使用情况dump到文件中 通过jhat对dump文件进行分析 通过MAT工具对dump文件进行分析 MAT介绍 ...
- linux环境下内存溢出分析MAT
文章目录 1 下载及安装mat 1.1 下载地址 1.2 查看服务器版本 1.3 下载安装 2 配置 3 运行 4 分析 1 下载及安装mat 1.1 下载地址 https://www.eclipse ...
- JAVA内存泄露分析和解决方案及WINDOWS自带查看工具
JAVA内存泄露分析和解决方案及WINDOWS自带查看工具 Java内存泄漏是每个Java程序员都会遇到的问题,程序在本地运行一切正常,可是布署到远端就会出现内存无限制的增长,最后系统瘫痪,那么如何最 ...
- Linux下tomcat内存溢出分析及优化
为什么80%的码农都做不了架构师?>>> 常见的内存溢出有以下两种: java.lang.OutOfMemoryError: PermGen space java.lang.O ...
- POI解决读入Excel内存溢出
POI读取excel表 下面是结构图 大批量数据读取的问题 在项目中遇到二十万行数据的excel用poi读取会内存溢出,一般方法是调大tomcat的内存,但是调到2048M还是会内存溢出报错 poi官 ...
- Java内存溢出分析
内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知道在什么时候或是在什么操作步骤上出现了异常,而且根据堆栈信息也很容易定位到程序中是某处出现了问题.内存溢出与锁表则不然,一 ...
最新文章
- spring-amqp整合rabbitmq消费者配置和代码
- RT-Thread GCC VSCode等开源工具链 在智能小车制作中的应用
- 如何为从1到10万用户的应用程序,设计不同的扩展方案?
- mongoDB的shell数组操作器
- TensorFlow for Hackers - Part III
- [Lua学习]简单链表
- 数据结构(三)之单链表反向查找
- java中遍历树形菜单,你可能不知道还有这样的方法
- Eclipse把默认为Gbk的编码变为UTF-8
- Python遍历字典的四种方法对比
- 创建接口匿名实现类的对象的四种方法
- Node 中的开发环境与生产环境 和 使用Morgan打印请求信息
- Qt从入门到放弃_0x01:建立项目
- Delphi -- 农历算法
- 计算机二级考试谁监考,【考证】你们要的计算机二级考试攻略来了!!!
- mysql查询父子关系树_数据库 SQL 遍历父子关系表(二叉树)获得所有子节点 所有父节点...
- 设计模式:简单的鸭子模型(入门)
- 雅诗兰黛公司宣布晋升Stéphane de La Faverie为集团总裁
- 微信发红包的测试用例功能点
- 科普系列:AUTOSAR与OSEK网络管理比较(上)