今天在进行使用 jxl 进行 Excel 下载时,由于数据量大(4万多条接近5万条数据的下载),数据结构过于负责,存在大量大对象(虽然在对象每次用完都设置为null,但还是存在内存溢出问题),加上本地电脑内存不大(只有8G),导致下载数据时报堆内存溢出,下载失败。

Exception data: java.lang.OutOfMemoryError
at jxl.write.biff.MemoryDataOutput.write(MemoryDataOutput.java:72)
at jxl.write.biff.File.write(File.java:149)
at jxl.write.biff.RowRecord.writeCells(RowRecord.java:324)
at jxl.write.biff.SheetWriter.write(SheetWriter.java:479)
at jxl.write.biff.WritableSheetImpl.write(WritableSheetImpl.java:1431)
at jxl.write.biff.WritableWorkbookImpl.write(WritableWorkbookImpl.java:915)

  下面是案例复现的简单模拟代码:

        <dependency>
<groupId>net.sourceforge.jexcelapi</groupId >
<artifactId>jxl</artifactId >
<version>2.6.12</version >
</dependency >
public class MyExcel {
public static void main(String[] args) throws Exception {
File xlsFile = new File("E:\\jxl.xls");
// 创建一个工作簿
WritableWorkbook workbook = Workbook.createWorkbook(xlsFile);
// 创建一个工作表
WritableSheet sheet = workbook.createSheet("sheet1", 0);
Map<Integer, ArrayList<Map<Integer, Person>>> mapListMap = new HashMap<>();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBatisConfig.class);
PersonServiceImpl bean = context.getBean(PersonServiceImpl.class);
//获取数据库数据
List<Person> listBean = bean.getList();
//进行数据处理
for (int row = 0; row < 45000; row++) {
ArrayList<Map<Integer, Person>> listMap = new ArrayList<Map<Integer, Person>>();
for (int col = 0; col < 30; col++) {
Map<Integer, Person> map = new HashMap<Integer, Person>();
for (int j = 0; j < listBean.size(); j++) {
map.put(j, listBean.get(j));
}
listMap.add(map);
map = null;
}
mapListMap.put(row, listMap);
listMap = null;
}
//写数据
for (int row = 0; row < 45000; row++) {
ArrayList<Map<Integer, Person>> listMap = mapListMap.get(row);
for (int col = 0; col < 30; col++) {
Map<Integer, Person> map = listMap.get(col);
for (int j = 0; j < listBean.size(); j++) {
Person person = map.get(j);
sheet.addCell(new Label(col, row, person.getId()+"" + row + col));
sheet.addCell(new Label(col, row, person.getName() + row + col));
sheet.addCell(new Label(col, row, person.getAge()+"" + row + col));
map = null;
}
}
listMap = null;
}
workbook.write();
workbook.close();
}

  运行后结果:

  解决办法:

  (1)最简单的方法是加大内存,本地电脑内存过小,当把代码部署到公司测试环境(测试环境内存是16G)时该问题不再复现;

  (2)采用临时文件写入EXCEL功能,设定临时文件的位置,可以有效的避免内存溢出(jxl版本必须是2.6.12及其以上,2.6版本没有采用临时文件的功能);

public static void main(String[] args) throws Exception {
File xlsFile = new File("E:\\jxl.xls");
// 创建一个工作簿
WorkbookSettings ws = new WorkbookSettings();
ws.setUseTemporaryFileDuringWrite(true);
ws.setTemporaryFileDuringWriteDirectory(new File("E:\\"));//指定一个临时文件路径
WritableWorkbook workbook = Workbook.createWorkbook(xlsFile,ws);
// 创建一个工作表
WritableSheet sheet = workbook.createSheet("sheet1", 0);
Map<Integer, ArrayList<Map<Integer, Person>>> mapListMap = new HashMap<>();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBatisConfig.class);
PersonServiceImpl bean = context.getBean(PersonServiceImpl.class);
//获取数据库数据
List<Person> listBean = bean.getList();
//进行数据处理
for (int row = 0; row < 45000; row++) {
ArrayList<Map<Integer, Person>> listMap = new ArrayList<Map<Integer, Person>>();
for (int col = 0; col < 30; col++) {
Map<Integer, Person> map = new HashMap<Integer, Person>();
for (int j = 0; j < listBean.size(); j++) {
map.put(j, listBean.get(j));
}
listMap.add(map);
map = null;
}
mapListMap.put(row, listMap);
listMap = null;
}
//写数据
for (int row = 0; row < 45000; row++) {
ArrayList<Map<Integer, Person>> listMap = mapListMap.get(row);
for (int col = 0; col < 30; col++) {
Map<Integer, Person> map = listMap.get(col);
for (int j = 0; j < listBean.size(); j++) {
Person person = map.get(j);
sheet.addCell(new Label(col, row, person.getId()+"" + row + col));
sheet.addCell(new Label(col, row, person.getName() + row + col));
sheet.addCell(new Label(col, row, person.getAge()+"" + row + col));
}
          map = null;
}
listMap = null;
}
workbook.write();
workbook.close();
}

  当开始执行下载时,会产生一个临时文件,jxl 会把数据写入到这个临时文件中,写入结束后会把这个临时文件删除:

  PS:

  (1)Excel 表一个 sheet 页可以存储6万条,所以一般超过5万条的,其他的数据就存储其他sheet中;或采用分成几个 Excel 表来实现数据下载;

  (2)今天测试下载的 Excel 数据文本有170M(数据有4.8w条),通过MS Office 打开失败,为空 Excel 表,但通过 WPS 可以正常打开。

自己挖的坑自己填--jxl进行Excel下载堆内存溢出问题的更多相关文章

  1. Redis采坑(一)——数据无法插入,内存溢出

    一.采坑背景 在最大数据分析的过程中,redis是被当做热数据的缓存库使用的,在某一天中,redis数据库热数据无法插入,此时数据量大概在100万左右,很是纠结,为什么不能插入?程序的错误,不可能,没 ...

  2. 自己挖的坑自己填--JVM报内存溢出

    在写定时任务时,对表数据进行批量操作,测试数据有10万条左右,在测试时发现跑着跑着出现内存溢出现象,最后发现创建的对象paramList 和tmBeanList没有被回收,经过资料查找,发现是循环内不 ...

  3. 自己挖的坑自己填--docker创建实例出现Waiting for SSH to be available…

    在之前使用Docker for Windows Installer.exe直接安装,通过docker-machine-driver-vmwareworkstation.exe实现docker和VM的共 ...

  4. 自己挖的坑自己填-- maven打jar包部署服务器报错

    1.今天 mvn install 后把 jar 包部署到服务器上,执行 java -jar xx.jar 报 "no main manifest attribute,in xx.jar&qu ...

  5. 自己挖的坑自己填--Mybatis mapper文件if标签中number类型及String类型的坑

    1.现象描述 (1)使用 Mybatis 在进行数据更新时,大部分时候update语句都需要通过动态SQL进行拼接.在其中,if标签中经常会有 xxx !='' 这种判断,若 number 类型的字段 ...

  6. 挖个坑,写一个Spring+SpringMVC+Mybatis的项目

    想挖个坑督促自己练技术,有时候想到一个项目,大概想了一些要实现的功能,怎么实现.现在觉得自己差不多能完成QQ空间的主要功能了.准备立个牌坊,写一个类似功能的网站.并且把进度放到这里来. 初步计划实现以 ...

  7. JAVAFX之tableview界面实时刷新导致的内存溢出(自己挖的坑,爬着也要出来啊0.0)

    这几天遇到了一个问题,不幸开发的一个cs架构的工具,客户端开启后,内存一直在缓慢增长最终导致进程卡死,花了4天时间,终于爬出来了... 客户端通过timer定时器每30秒查询一次数据库以及一些业务逻辑 ...

  8. jxl导出Excel中需要跳过的的坑

    正如上篇文章(JXL封装不能使用static关键字问题)所说,在jxl导出Excel时候如果频繁使用到WritableCellFormat去设置单元格的样式,这个时候经常会出现两种情况: 1.报警告: ...

  9. java利用jxl操作Excel

    /** * 把从数据库查询到的数据,写入电子表格 * * @throws Exception */ public void createXls() throws Exception { Dao dao ...

随机推荐

  1. 使用 js 实现一个简易版的模版引擎

    使用 js 实现一个简易版的模版引擎 regex (function test() { this.str = str; })( window.Test = ...; format() { let ar ...

  2. How to using PyPI publish a Python package

    How to using PyPI publish a Python package PyPI & Python package https://pypi.org/ main make a f ...

  3. CSS Learning Paths

    CSS Learning Paths CSS Expert refs https://developer.mozilla.org/en-US/docs/Web/CSS https://css-tric ...

  4. chrome device remote debug

    chrome device remote debug chrome://inspect/#devices chrome inspect devices Android chrome MIDI / MT ...

  5. taro 如何展示多行文本 省略号

    taro 如何展示多行文本 省略号 webkit-box-orient: vertical; See the Pen Pure CSS multiline text with ellipsis by ...

  6. how to get svg text tspan x,y position value in js

    how to get svg text tspan x,y position value in js <svg xmlns="http://www.w3.org/2000/svg&qu ...

  7. NGK算力生态建设者狂欢!SPC之后又有VAST!

    想致富,先挖矿.这句话已经成为了币圈的一句名言.挖矿一词始终贯穿着区块链以及数字加密领域. 据小道消息透露,NGK官最近将会推出两款挖矿产品---SPC星空币以及其子币VAST维萨币. 下面笔者就来一 ...

  8. springboot项目打包成jar包在Linux服务器默认80端口运行

    springboot项目端口设置 在application.properties文件 server.port=80 在application.yml文件 server: port: 80 然后在ide ...

  9. 顶级c程序员之路 基础篇 - 第一章 关键字的深度理解 number-1

    c语言有32个关键字,每个关键字你都理解吗? 今天出场的是: auto ,  register,  static,   extern 为什么他们会一起呢,说到这里不得不谈到c语言对变量的描述. c给每 ...

  10. 后端程序员之路 40、Pthreads

    POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准.线程这个东西在操作系统原理里讲得比较清楚了,再加上对windows那一套进程线程的东西比较清楚,所以这里还是 ...