在使用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 more if(! 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 LabelSSTRecord convertLabelRecords(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(); } }
相关推荐
poi读取大量数据会造成gc内存溢出的报错,由于垃圾回收机制无法将大量的对象及时的回收,而这些对象又会保存在内存中,会导致内存不够用的情况,这时候我们就需要使用新的方法,读取为cvs即可.此解决方案可支持千万数据的...
在处理大型Excel 2007(.xlsx)文件时,Apache POI是一个常见的Java库,但不恰当的使用方式可能会导致内存溢出错误。这是因为POI默认会将整个工作簿加载到内存中,对于大文件,这显然是不可行的。为了解决这个问题,...
文章深入分析了内存溢出的具体表现形式,并提供了相应的解决方案。 #### 内存溢出类型及原因分析 内存溢出主要分为三种类型: 1. **Java heap space** - **原因**:当JVM的堆内存不足以存储更多的数据时会发生...
在Java开发中,当面临大批量数据导出到Excel文件时,可能会遇到内存溢出的问题。这是因为Excel文件格式本身的设计,以及Java默认处理大数据的方式,可能导致内存占用过高,尤其是在一次性加载大量数据到内存中进行...
在处理大量数据时,使用 POI 的默认用户模式(UserModel)读取 Excel 文件可能会导致内存溢出问题,因为该模式会将整个文件加载到内存中。本文将详细介绍如何解决由 POI 用户模式引发的内存溢出问题,并提供相应的...
本解决方案主要针对使用Apache POI库进行Excel读取时遇到的这类问题。 首先,Apache POI是Java中广泛使用的处理Microsoft Office文档(包括Excel)的库。在处理大文件时,POI会将整个工作簿加载到内存中,当文件过...
这有助于控制内存使用,但对处理海量数据来说,使用SXSSFWorkbook是更有效的解决方案。 总之,处理Java中Excel的海量数据时,应优先考虑使用SXSSF,以降低内存需求并避免内存溢出。同时,合理配置JVM内存参数也是必...
3. 调整JVM内存设置:增加JVM的堆内存大小(通过-Xms和-Xmx参数),但这只是临时解决方案,并不能从根本上解决问题,因为增加内存可能导致其他性能问题。 4. 使用内存映射文件(Memory-Mapped Files):虽然JXL不...
- **性能优化**:由于大文件可能导致内存溢出,可以考虑使用SXSSF(Streaming Usermodel API)进行大文件处理,它允许数据按需写入磁盘,减少内存消耗。 5. **项目结构** - `.classpath` 和 `.project` 是Eclipse...
事件驱动解析是把文件转换成xml,然后一边读取一边解析,这样就对内存的占用就会很少,可以很好的处理poi出现OOM的问题。 maven添加需要的jar包 <groupId>org.apache.poi <artifactId>poi <version>3.15 ...
对于大规模数据处理,JXL可能会遇到行数限制或内存溢出等问题。 - **POI**:POI在处理大型文件方面表现出更强的能力,能够支持超过65535行的数据量。尽管如此,在处理非常大的文件时,也需要考虑内存管理和性能优化...
"快速、简洁、解决大文件内存溢出的java处理Excel工具" 提供了这样的解决方案,它很可能是指阿里巴巴的开源项目EasyExcel。 EasyExcel是一款基于Java的开源Excel读写框架,它的设计目标就是为了高效、低内存消耗地...
POI项目始于2002年,旨在为Java开发者提供一种处理这些文件的纯Java解决方案,避免了对Microsoft Office的依赖。 **Excel支持** 在"poi-3.9"版本中,POI提供了对两种Excel文件格式的支持: 1. **HSSF (Horrible ...
4. **内存管理和性能优化**:对于大型文件,POI提供SXSSF API作为内存管理优化的解决方案,它使用滑动窗口模型,只在内存中保持最近使用的部分数据,其余数据写入磁盘,有效降低了内存占用。 5. **事件模型API...
5. **高效性能**:POI库被设计为内存效率高,可以在大文件处理时避免内存溢出问题。例如,可以使用流式API来处理大型Excel文件,而不是一次性加载整个文件到内存。 6. **API简单易用**:POI提供了一套清晰、直观的...
【标题】"POI教程"涉及的是Apache POI库在Java中处理Microsoft Office...通过这些知识点的学习,开发者可以熟练掌握使用Apache POI进行Java与Excel交互的技能,提升工作效率,并为处理大规模Excel数据提供解决方案。
Excel文件通常存储为二进制格式,如`.xls`或`.xlsx`,这些文件可以容纳大量的行和列,但当数据量过大时,可能会引发内存溢出(Out Of Memory, OOM)错误。在这种情况下,我们需要对代码进行优化以避免此类问题。本篇...
7. **内存管理**:处理大型Office文件时,可能会遇到内存溢出问题。适当调整JVM的堆大小,或者使用POI的低内存设置,如`SXSSFWorkbook`代替`XSSFWorkbook`。 8. **异常处理**:确保捕获并处理可能出现的异常,如`...