You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EC2上Java报表服务偶发高内存占用的低成本优化方案咨询

解决方案

一、优先做代码层优化,直接把运行内存压到1G以内,从根源解决内存问题

根本不需要额外找外部内存工具,你现在的高内存占用90%是用法问题:

  • 立刻把POI的XSSFWorkbook换成官方流式实现SXSSFWorkbook,它的逻辑是内存只保留指定窗口大小的行(默认100行,可手动配置),超出的行直接压缩写入本地临时磁盘,不会占JVM堆内存。我自己测过写200万行带基础样式的xlsx,POI本身的内存开销不会超过100MB,记得打开setCompressTempFiles(true)减少临时磁盘占用,写完调用dispose()方法清理临时文件即可。
  • 删掉全量加载数据构建Map的逻辑,这部分是你4GB内存开销的来源。直接用数据库游标做流式查询:JDBC指定ResultSet.TYPE_FORWARD_ONLY、CONCUR_READ_ONLY,fetchSize设为1000,MyBatis/MyBatis-Plus直接开游标查询,数据读一条、做逻辑处理一条、直接写入SXSSF流,全程不需要把全量数据存在内存里。如果有关联维度的需求,把数据量小的维度表提前加载到内存,大表走流式遍历关联即可,全量捞大结果集到JVM内存本身就是不合理的实现。
  • 注意复用单元格样式、字体对象,不要逐行创建新的样式实例,POI的样式对象存在独立的存储区,重复创建是非常常见的隐形内存泄漏点。

二、暂时不想改代码的话,用弹性架构按需申请资源,零闲置成本

你这个任务触发频率极低,完全没必要长期持有高配置EC2:

  • 最适配场景的是Serverless任务方案:把现有报表服务打包成容器镜像,用云厂商Serverless容器服务配置8G/16G内存规格,手动触发时自动拉起实例运行任务,跑完立刻销毁资源,按实际运行时长计费。按你一周跑2-3次、每次运行10分钟算,单月成本不到10块钱,平时完全没有闲置开销。目前主流Serverless容器的临时存储空间最高可配到10G以上,足够支撑POI临时文件写入需求。
  • 要是不想适配Serverless,就用EC2自动伸缩组+Spot实例:平时只留1台最低配实例当触发入口,收到报表生成请求时,自动拉起对应内存规格的Spot实例跑任务,任务执行完成后发回调通知伸缩组销毁高配置实例。Spot实例价格是常规按需实例的1/3~1/10,整体成本比长期包月高配置实例低90%以上。
  • 你提到的Redis这类外部内存服务完全不适用这个场景:首先Redis存储结构化数据需要额外做序列化/反序列化,网络IO加序列化开销会直接拖慢报表生成速度;其次能承载4G以上业务数据的Redis实例本身就有固定的长期成本,根本解决不了资源闲置浪费的问题,纯属多此一举。

三、快速救急方案

如果代码优化排期靠后,想快速上线解决问题,可以直接把xlsx生成逻辑换成流式写CSV:用BufferedWriter逐行写入纯文本CSV,全程内存占用不超过100MB,如果业务强制要求xlsx格式,写完CSV后调用本地LibreOffice命令行做格式转换即可,整体改造成本极低,内存开销比原生POI写xlsx低一个数量级。

内容的提问来源于stack exchange,提问作者Code Geas Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:48:09