今天在进行使用 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. C# 6.0 Features , C# 7.0 Features

    1 1 1 C# 6.0 Features http://stackoverflow.com/documentation/c%23/24/c-sharp-6-0-features#t=20160828 ...

  2. SwiftUI All In One

    SwiftUI All In One SwiftUI SwiftUI is an innovative, exceptionally simple way to build user interfac ...

  3. jest all in one

    jest all in one ES Modules & TypeScript & React https://github.com/xgqfrms/FEAT/tree/master/ ...

  4. console.log & front-end jobs

    console.log & front-end jobs bind & function let log = console.log; let obj = {}; log(obj); ...

  5. website url spam

    website url spam xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  6. asm 查看字节码

    a.asm global Start section .text inc dword [esi] push edi mov edi,[esp+0x14] λ nasm -f win32 a.asm - ...

  7. 「NGK每日快讯」2021.2.3日NGK公链第92期官方快讯!

  8. Renice INC:不同颜色的酒帽所代表的意义

    酒帽就是酒瓶上方的热缩胶帽/锡帽/蜡封,也就是开瓶前要割掉的那一层保护物,所有的法国酒在酒帽上,都会有一个圆形贴纸,除了有不同颜色外,上面还有一串号码,有可能很多人在喝酒时都不会对这个酒帽有更多的在意 ...

  9. NGK创造的BGV金融世界观是什么?

    目前DeFi已经形成初级的金融体系.笔者将DeFi市场对比传统金融世界观,不过市场结构有显着差异.我们可以这样想:如果在去中心化金融世界中借钱,那么可以把MakerDAO比作为中央银行(+回购). 去 ...

  10. 一周精彩内容分享(第 3 期):开工大吉的 B 面

    这里记录过去一周,我看到的值得分享的东西. 一方面是整理记录一下自己一周的学习,另一方面也是期待自己有更多的输出,有更多的价值. 周刊开源(Github:wmyskxz/weekly),欢迎提交 is ...