使用POI-10遇到的OOM问题

Maven依赖:
	
	<dependency>
		<groupId>org.apache.poi</groupId>
		<artifactId>poi</artifactId>
		<version>3.10-FINAL</version>
	</dependency>
	<dependency>
		<groupId>org.apache.poi</groupId>
		<artifactId>poi-ooxml</artifactId>
		<version>3.10-FINAL</version>
	</dependency>
	
	
举例:

	import java.io.FileOutputStream;

	import org.apache.poi.ss.usermodel.Row;
	import org.apache.poi.ss.usermodel.Sheet;
	import org.apache.poi.xssf.streaming.SXSSFWorkbook;
	import org.apache.poi.xssf.usermodel.XSSFWorkbook;


	public class PoiTest {

		/*	testGenerateXSSFWorkbook
			性能分析:
				1)Workbook这个对象一直在不断增大,占用了堆中的大量空间,从而导致GC
				2)但是这个对象仍然在引用链上,故不会被回收掉,进而JVM会频繁地GC
				3)经过多次GC后,这个对象已经进入老年代,故JVM会进行Full GC
				4)JVM在进行了大量的Full GC后仍然没有更多可用的空间,最终导致堆内存溢出。
		
			优化方案:
				数据比较大时,将内存中的数据刷新到磁盘中,减少内存的使用量,进而减少GC的次数,起到以空间换时间作用,提高效率。
		*/
		public static void testGenerateXSSFWorkbook() {
			System.out.println("开始生成Excel文件。");
			
			Long start = System.currentTimeMillis();
			
			XSSFWorkbook wb = new XSSFWorkbook();
			
			// 创建并初始化sheet
			Sheet sheet = wb.createSheet("测试计划");
			int rowNumber = 10000 * 100; // 行数
			int columnNumber = 8; // 列数
			int count = 0;
			for (int i = 0; i < rowNumber; i++) {
				// 创建行
				Row row = sheet.createRow(i);
				for (int j = 0; j < columnNumber; j++) {
					// 创建单元格并赋值
					String cellValue = "测试内容:这是cell的内容";
					row.createCell(j).setCellValue(cellValue);
				}
				System.out.println(count++);
			}
		
			Long end = System.currentTimeMillis();
			System.out.println("XSSFWorkbook constructed. " + "Cost:" + (end - start) + " ms");
			
			try {
				wb.write(new FileOutputStream("C:/Users/jinxiaoning/Desktop/aaa/测试.xlsx"));
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println("成功生成Excel文件。");
			
			// 说明:在-Xmx4096m -Xms4096m 下,执行到501053行时,内存基本就被打满了,程序几乎不在向下进行了!
		}
		
		
		/**
		 * 优化
		 */
		public static void testGenerateSXSSFWorkbook() {
			System.out.println("开始生成Excel文件。");
			
			Long start = System.currentTimeMillis();
			
			int memoryRowNum = 200;
			
			// keep memoryRowNum rows in memory, exceeding rows will be flushed to disk ,memoryRowNum 默认是100
			SXSSFWorkbook wb = new SXSSFWorkbook(memoryRowNum);
			
			// whether to use gzip compression for temporary files 是否对刷新到磁盘上的临时文件进行压缩
			wb.setCompressTempFiles(true);
			
			// 创建并初始化sheet
			Sheet sheet = wb.createSheet("测试计划");
			int rowNumber = 10000 * 100; // 行数
			int columnNumber = 8; // 列数
			int count = 0;
			for (int i = 0; i < rowNumber; i++) {
				// 创建行
				Row row = sheet.createRow(i);
				for (int j = 0; j < columnNumber; j++) {
					// 创建单元格并赋值
					String cellValue = "测试内容:这是cell的内容";
					row.createCell(j).setCellValue(cellValue);
				}
				System.out.println(count++);
			}
		
			Long end = System.currentTimeMillis();
			System.out.println("SXSSFWorkbook constructed. " + "Cost:" + (end - start) + " ms");
			
			try {
				wb.write(new FileOutputStream("C:/Users/jinxiaoning/Desktop/aaa/测试.xlsx"));
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println("成功生成Excel文件。");
			
			// 补充:sheet.getRow(rownum)方法只能获取到内存中的数据(即:只能获取最近memoryRowNum行的数据),不能获取序列化到磁盘上的数据。
			
		}
		

		public static void main(String[] args) throws Throwable {  
			
			testGenerateXSSFWorkbook();
	//		testGenerateSXSSFWorkbook();
		} 
		
	}

	
	优化方法testGenerateSXSSFWorkbook()执行的结果:
	
		生成的Excel文件:
			测试.xlsx大小为19.9M

		不压缩临时文件结果:
			时间:SXSSFWorkbook constructed. Cost:64697 ms
			临时文件:
				大小:983M
				位置:C:\Users\jxn\AppData\Local\Temp\poi-sxssf-sheet136052270586183201.xml
			
		压缩临时文件的结果:
			时间:SXSSFWorkbook constructed. Cost:67774 ms
			临时文件:
				大小:19.9M,与生成的Excel文件的大小几乎相等。
				位置:C:\Users\jxn\AppData\Local\Temp\poi-sxssf-sheet-xml5730563994406788419.gz
				说明:poi-sxssf-sheet-xml5730563994406788419.gz解压后得到的文件poi-sxssf-sheet-xml5730563994406788419大小为983M

		针对内存中数据的行数memoryRowNum的测试结果:
		
			1000 不压缩:SXSSFWorkbook constructed. Cost:63350 ms
			10	 不压缩:SXSSFWorkbook constructed. Cost:63097 ms




 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值