You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Apache POI生成Excel占用CPU过高,如何优化?

嘿,我来帮你解决这个Apache POI生成Excel的性能瓶颈问题!你遇到的单文件占50%CPU、多并发直接崩服务器的情况,多半是因为当前的实现方式没利用好POI的优化特性,同时并发控制也没跟上。下面给你几个落地性强的优化方案:

1. 立刻切换到SXSSFWorkbook(最核心的优化)

你当前使用的HSSFWorkbook是针对旧版xls格式的实现,它会把整个Excel的所有数据都加载在内存中,数据量稍大就会导致内存和CPU占用飙升。换成SXSSFWorkbook(XSSF的流式处理版本,支持xlsx格式)就不一样了——它会把超过指定行数的数据自动写到临时文件里,只在内存中保留一小部分“窗口数据”,能直接把内存占用降到原来的几十分之一,CPU消耗也会大幅降低。

代码替换非常简单:

// 替换原来的HSSFWorkbook,100表示内存中保留的行数,可根据你的数据量调整
final Workbook workbook = new SXSSFWorkbook(100);

注意:如果业务必须要生成xls格式,这条不适用,但优先推荐切换到xlsx,毕竟xls有65536行的行数限制,性能差距真的很大。

2. 优化数据写入的细节,减少不必要的计算

看你代码里的buildBomSheet方法,这些细节能帮你进一步降低CPU消耗:

  • 复用CellStyle和DataFormat:不要每次创建单元格都新建样式,样式是POI中比较重的对象,重复创建会触发大量重复计算。你的initDataFormat方法可以改成提前创建好所有需要的样式,存在一个Map里,后续创建单元格时直接取用。
  • 批量操作优先:避免逐行逐单元格频繁调用POI的API,比如可以一次性设置所有列的列宽,批量创建行和单元格后再统一赋值,减少POI内部的状态刷新次数。
3. 严格控制并发请求数量,防止资源耗尽

服务器崩溃的本质是并发生成时CPU、内存被彻底占满,必须做并发控制:

  • 用线程池限制同时处理Excel生成请求的线程数:比如根据服务器CPU核心数来设置,4核CPU的话,核心线程数设为2-4,最大线程数不超过8,避免过多线程抢占资源。
  • 给请求加超时限制:如果某个Excel生成请求耗时过长,直接中断并释放资源,防止它一直占用CPU和内存。
  • 前端限流(如果是Web应用):限制用户同时只能发起一个导出请求,避免多用户同时导出导致服务雪崩。
4. 调整服务器和JVM配置,给POI足够的资源空间
  • 增大JVM堆内存:比如把-Xmx参数设为4G(根据服务器实际内存调整,8G内存的服务器可以设到4-6G),避免因为内存不足触发频繁的GC,GC本身就会占用大量CPU。
  • 确保临时磁盘有足够空间:SXSSF会用到临时文件存储溢出的数据,如果磁盘满了会导致写入失败,甚至服务崩溃。
5. 优化输出流的写入方式(可选)

你现在直接调用workbook.write(response.getOutputStream()),如果网络传输较慢,这个过程会一直占用POI的资源和线程。可以改成:

  • 先把Excel写到本地临时文件,再用NIO的方式把文件内容传输给Response,让POI的写入和网络传输解耦。
  • 用异步Servlet处理导出请求,让生成Excel的线程和处理HTTP响应的线程分开,减少线程阻塞时间。

内容的提问来源于stack exchange,提问作者Alexandre

火山引擎 最新活动