方式1:通过工具类ExcelExportUtil.exportExcel导出
//常驻内存:HSSFCell等
ExportParams params = new ExportParams();
params.setAddIndex(true);
Workbook workbook=null;
Date start = new Date();
FileOutputStream out = new FileOutputStream("ooxml-scatter-chart_SXSSFW_.xlsx");
List<MsgClient> list = new ArrayList<MsgClient>();
for (int i = 0; i < 1000000; i++) { //一百万数据量
MsgClient client = new MsgClient();
client.setBirthday(new Date());
client.setClientName("小明" + i);
client.setClientPhone("18797" + i);
client.setCreateBy("JueYue");
client.setId("1" + i);
client.setRemark("测试" + i);
MsgClientGroup group = new MsgClientGroup();
group.setGroupName("测试" + i);
client.setGroup(group);
list.add(client);
}
workbook = ExcelExportUtil.exportExcel(new ExportParams(), MsgClient.class, list);
workbook.write(out);
out.close();
System.out.println(new Date().getTime() - start.getTime());
通过jvisualvm观察内存和cpu使用情况:

从图上可以看到cpu和内存使用情况,最坏的情况下可能需要接近3个G的内存,除了本身list的对象没有释放外,还有很多是跟esaypoi相关的对象没有被释放。
可以看下第二个图,堆dump:

从图中可以看到本身MsgClient对象大概40w个,,但是和easypoi的对象400w个
时间往后再看:

这个时候我们的MsgClient对象已被回收,但是easypoi的对象达到了700w。
所以这种方式下的导出,cpu和内存需求都比较大。
这种方式导出100w条数据花费时间92s。
方式2:通过工具类ExcelExportUtil.exportBigExcel导出。
这种方式下,实例化的workbook为,SXSSFWorkbook,他本身默认只保持100条只读的数据在内存中,其他的会写到磁盘临时文件。直接看代码:
List<MsgClient> list = new ArrayList<MsgClient>();
Workbook workbook = null;
Date start = new Date();
ExportParams params = new ExportParams("大数据测试", "测试");
for (int i = 0; i < 1000000; i++) { //一百万数据量
MsgClient client = new MsgClient();
client.setBirthday(new Date());
client.setClientName("小明" + i);
client.setClientPhone("18797" + i);
client.setCreateBy("JueYue");
client.setId("1" + i);
client.setRemark("测试" + i);
MsgClientGroup group = new MsgClientGroup();
group.setGroupName("测试" + i);
client.setGroup(group);
list.add(client);
if(list.size() == 10000){
workbook = ExcelExportUtil.exportBigExcel(params, MsgClient.class, list);
list.clear();
}
}
ExcelExportUtil.closeExportBigExcel();
System.out.println(new Date().getTime() - start.getTime());
File savefile = new File("D:/excel/");
if (!savefile.exists()) {
savefile.mkdirs();
}
FileOutputStream fos = new FileOutputStream("D:/excel/ExcelExportBigData.bigDataExport.xlsx");
workbook.write(fos);
fos.close();
从代码上可以看出,首先MsgClient的对象可以分段去写到workbook中,这样可以进一步降低内存的使用情况。
通过jvisualvm监控,我们看下内存和cpu的使用情况

从cpu和内存使用情况上看,使比方式一,cpu能够比较平稳,内存使用接近在1G的水平,当然可以通过限制堆内存大小来随时进行垃圾回收(亲测512m或者256m都是没问题的)。
然后看看dump文件的数据:

主要还是我们自定义的对象占据了比较多的实例和内存。

再看看easypoi的对象实例数,想SXSSFCELL,为什么是700,这里我的列是7列,然后100行在内存,最终就是700个对象,这样反向证明了默认是100个行数据在内存。
该方式下,导出100w条数据耗时14s。
网友评论