news 2026/10/21 10:34:35

自己挖的坑自己填--jxl进行Excel下载堆内存溢出问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自己挖的坑自己填--jxl进行Excel下载堆内存溢出问题

源码仓库:Gitee · GitHub

今天在进行使用 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 会把数据写入到这个临时文件中,写入结束后会把这个临时文件删除:

经过 jconsole.exe 监控可以看出:使用了临时文件后多了一个线程进行类的卸载,使用了临时文件的线程高峰有15个,类卸载了6个,没有使用临时文件时线程数一直保持14个到报内存溢出结束,0个类卸载:

PS:

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 10:33:02

GD32H759 RT-Thread USB CDC ACM虚拟串口移植实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 10:32:08

计量芯片通讯报文校验和机制:量产隐患与排查优化全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 10:31:52

AI芯片选型指南:从TOPS误区到四维筛选与实测避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 10:31:52

SPI与I2C通信原理、物理层陷阱与驱动实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 10:31:28

RTOS任务详解:从状态机到调度器,一次搞懂嵌入式多任务核心

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 10:30:11

先别买STM32开发板!3-5年职场人跨界嵌入式的迁移评估清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华