常用导出方式
- POI (Apache)
- org.apache.poi.hssf.usermodel.HSSFWorkbook
- org.apache.poi.xssf.streaming.SXSSFWorkbook
- EasyExcel(阿里巴巴)
- com.alibaba.excel.ExcelWriter
比较内存消耗情况
单线程测试用例
- 由于 GC 的影响,这些测试数据不是非常准确,但是还是有一些参考意义。
- 测试导出 6 万条记录,观察导出的过程中,内存的消耗情况:
- HSSFWorkbook
- SXSSFWorkbook
- ExcelWriter
- HSSFWorkbook
多线程测试用例
- 10 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息:
- HSSFWorkbook 的导出:
- 正常导出,消耗 920M左右内存,最慢 27秒。
- SXSSFWorkbook 的导出:
- 正常导出,消耗内存 183 M,最慢 12 秒。
- HSSFWorkbook 的导出:
- 20 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
- HSSFWorkbook 的导出:
- 内存溢出,导出失败:
- SXSSFWorkbook 的导出:
- 正常导出,内存消耗 388 M,最慢的线程需要 17秒。
- HSSFWorkbook 的导出:
- 30 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
- HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
- SXSSFWorkbook :
- 正常导出,内存消耗440M,耗时 25 秒。
- 40 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
- HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
- SXSSFWorkbook :
- 正常导出,内存消耗670M,耗时 33 秒。
- 50 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
- HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
- SXSSFWorkbook :
- 正常导出,内存消耗560M(触发了内存回收,博主测了几组都差不多),耗时 38 秒。
- 100 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
- HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
- SXSSFWorkbook :
- 正常导出,内存消耗269M(触发了内存回收,博主测了几组都差不多),耗时 75 秒。
简单总结与分析
- 从节省内存的角度看,SXSSFWorkbook 和 EasyExcel 相对于 HSSFWorkbook 有很大的优势。所以,并发数稍微高点,HSSFWorkbook 就会撑爆内存,而SXSSFWorkbook 和 EasyExcel 不会有这个问题,只是导出稍微慢点。
- 从导出速度上看,SXSSFWorkbook 和 EasyExcel 也比 HSSFWorkbook 快很多
- SXSSFWorkbook 消耗的内存少。内存消耗少的主要原因是它引入了 rowAccessWindowSize 。
- rowAccessWindowSize 的作用:
- rowAccessWindowSize 的作用:
- EasyExcel 同样内存消耗低。它是如何实现降低内存消耗???
- 楼主没有找到相关资料。
- 尝试分析:
- 要使得内存消耗小,肯定是把导出的数据存放到了内存之外的地方——显然,只有硬盘了。
- 博主猜测,EasyExcel 有和 SXSSFWorkbook 类似的机制,当存入的数据超出阈值之后,就先缓存到硬盘。在SXSSFWorkbook 中,阈值由 rowAccessWindowSize 确定,默认是 100 行。
- 博主多次执行 EasyExcel 的导出程序,发现很多时候 usedMemory 都很低。
- 博主猜测,如果不是碰巧,就是 EasyExcel 实现了控制 GC 的逻辑。
- 要使得内存消耗小,肯定是把导出的数据存放到了内存之外的地方——显然,只有硬盘了。
- 如何选择:
- SXSSFWorkbook 和 EasyExcel 任选一个。博主本人更倾向于使用 Apache 的 SXSSFWorkbook 。
- 文档多是一方面
- 和 HSSFWorkbook 一脉相承,都是 Workbook 的派生类。因此,我们要把 HSSFWorkbook 重构成 SXSSFWorkbook 会非常简单,只需要修改生成 Workbook 的具体类型,并在最后导出的时候,调用 SXSSFWorkbook 的 dispose() 方法即可。
- SXSSFWorkbook 内存消耗少的原因很透明-上面已经分析,不再赘述。而 EasyExcel 博主不太了解。但是经过博主简单的测试,EasyExcel 和 SXSSFWorkbook 不相伯仲,所以也就没有必要纠结 EasyExcel 。
- 注意,EasyExcel GitHub上的测试图,是 EasyExcel 和 HSSFWorkbook (而不是 SXSSFWorkbook )的比较结果。
- SXSSFWorkbook 和 EasyExcel 任选一个。博主本人更倾向于使用 Apache 的 SXSSFWorkbook 。