`

POI内存溢出分析及解决方案

    博客分类:
  • java
 
阅读更多

在使用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();  
	}
}

 

 

 

 

  • 大小: 38.2 KB
  • 大小: 17.1 KB
  • 大小: 16.1 KB
分享到:
评论

相关推荐

    poi大量数据读取gc内存溢出解决方案

    poi读取大量数据会造成gc内存溢出的报错,由于垃圾回收机制无法将大量的对象及时的回收,而这些对象又会保存在内存中,会导致内存不够用的情况,这时候我们就需要使用新的方法,读取为cvs即可.此解决方案可支持千万数据的...

    解决poi读取excel2007出现内存溢出问题代码参

    在处理大型Excel 2007(.xlsx)文件时,Apache POI是一个常见的Java库,但不恰当的使用方式可能会导致内存溢出错误。这是因为POI默认会将整个工作簿加载到内存中,对于大文件,这显然是不可行的。为了解决这个问题,...

    apache服务器出现内存溢出的解决方法.doc

    文章深入分析了内存溢出的具体表现形式,并提供了相应的解决方案。 #### 内存溢出类型及原因分析 内存溢出主要分为三种类型: 1. **Java heap space** - **原因**:当JVM的堆内存不足以存储更多的数据时会发生...

    java解决大批量数据导出Excel产生内存溢出的方案

    在Java开发中,当面临大批量数据导出到Excel文件时,可能会遇到内存溢出的问题。这是因为Excel文件格式本身的设计,以及Java默认处理大数据的方式,可能导致内存占用过高,尤其是在一次性加载大量数据到内存中进行...

    关于Poi读取Excel引发内存溢出问题的解决方法

    在处理大量数据时,使用 POI 的默认用户模式(UserModel)读取 Excel 文件可能会导致内存溢出问题,因为该模式会将整个文件加载到内存中。本文将详细介绍如何解决由 POI 用户模式引发的内存溢出问题,并提供相应的...

    完美解决java读取excel内存溢出问题.rar

    本解决方案主要针对使用Apache POI库进行Excel读取时遇到的这类问题。 首先,Apache POI是Java中广泛使用的处理Microsoft Office文档(包括Excel)的库。在处理大文件时,POI会将整个工作簿加载到内存中,当文件过...

    java向excel 写入海量数据内存溢出问题的解决.pdf

    这有助于控制内存使用,但对处理海量数据来说,使用SXSSFWorkbook是更有效的解决方案。 总之,处理Java中Excel的海量数据时,应优先考虑使用SXSSF,以降低内存需求并避免内存溢出。同时,合理配置JVM内存参数也是必...

    jxl写大文件时会出现内存溢出

    3. 调整JVM内存设置:增加JVM的堆内存大小(通过-Xms和-Xmx参数),但这只是临时解决方案,并不能从根本上解决问题,因为增加内存可能导致其他性能问题。 4. 使用内存映射文件(Memory-Mapped Files):虽然JXL不...

    通用的POI导入Excel解决方案

    - **性能优化**:由于大文件可能导致内存溢出,可以考虑使用SXSSF(Streaming Usermodel API)进行大文件处理,它允许数据按需写入磁盘,减少内存消耗。 5. **项目结构** - `.classpath` 和 `.project` 是Eclipse...

    poi:适合解析小的excel文件,文件稍微大一点就出现OOM。

    事件驱动解析是把文件转换成xml,然后一边读取一边解析,这样就对内存的占用就会很少,可以很好的处理poi出现OOM的问题。 maven添加需要的jar包 &lt;groupId&gt;org.apache.poi &lt;artifactId&gt;poi &lt;version&gt;3.15 ...

    POI与JXL的实战性能对比

    对于大规模数据处理,JXL可能会遇到行数限制或内存溢出等问题。 - **POI**:POI在处理大型文件方面表现出更强的能力,能够支持超过65535行的数据量。尽管如此,在处理非常大的文件时,也需要考虑内存管理和性能优化...

    快速、简洁、解决大文件内存溢出的java处理Excel工具

    "快速、简洁、解决大文件内存溢出的java处理Excel工具" 提供了这样的解决方案,它很可能是指阿里巴巴的开源项目EasyExcel。 EasyExcel是一款基于Java的开源Excel读写框架,它的设计目标就是为了高效、低内存消耗地...

    poi-3.9的jar包

    POI项目始于2002年,旨在为Java开发者提供一种处理这些文件的纯Java解决方案,避免了对Microsoft Office的依赖。 **Excel支持** 在"poi-3.9"版本中,POI提供了对两种Excel文件格式的支持: 1. **HSSF (Horrible ...

    POI,很全的jar包

    4. **内存管理和性能优化**:对于大型文件,POI提供SXSSF API作为内存管理优化的解决方案,它使用滑动窗口模型,只在内存中保持最近使用的部分数据,其余数据写入磁盘,有效降低了内存占用。 5. **事件模型API...

    poi-3.7.jar_java_POI_belongdbc_

    5. **高效性能**:POI库被设计为内存效率高,可以在大文件处理时避免内存溢出问题。例如,可以使用流式API来处理大型Excel文件,而不是一次性加载整个文件到内存。 6. **API简单易用**:POI提供了一套清晰、直观的...

    POI教程

    【标题】"POI教程"涉及的是Apache POI库在Java中处理Microsoft Office...通过这些知识点的学习,开发者可以熟练掌握使用Apache POI进行Java与Excel交互的技能,提升工作效率,并为处理大规模Excel数据提供解决方案。

    java poi 读取百万数据OOM优化

    Excel文件通常存储为二进制格式,如`.xls`或`.xlsx`,这些文件可以容纳大量的行和列,但当数据量过大时,可能会引发内存溢出(Out Of Memory, OOM)错误。在这种情况下,我们需要对代码进行优化以避免此类问题。本篇...

    org.apache.poi*jar包

    7. **内存管理**:处理大型Office文件时,可能会遇到内存溢出问题。适当调整JVM的堆大小,或者使用POI的低内存设置,如`SXSSFWorkbook`代替`XSSFWorkbook`。 8. **异常处理**:确保捕获并处理可能出现的异常,如`...

Global site tag (gtag.js) - Google Analytics