tomcat生成大报表时应设-xms与-xmx相等(如2g),堆上限按单次最大需求×1.5估算,新生代设为堆的1/3~1/2,启用g1gc并限制maxgcpausemillis=200,同时配置metaspacesize/maxmetaspacesize及减小xss至256k。

在线生成大报表时,Tomcat容易因瞬时对象激增(如大量List、Map、Excel缓存、数据库结果集)导致堆内存撑爆,触发 java.lang.OutOfMemoryError: Java heap space。关键不是盲目加内存,而是让堆分配匹配报表场景的“峰值压力”——既要留足空间扛住临时大对象,又要避免过大堆引发GC停顿过长或元空间/线程栈被挤压。
明确堆大小设置原则(不照搬物理内存比例)
报表类应用特点是:单次请求内存消耗高、持续时间短、并发数通常不高(比如后台导出,5~20人同时点)。因此:
-
-Xms 和 -Xmx 必须设为相同值,例如
-Xms2g -Xmx2g。避免运行中扩容触发Full GC,而报表生成过程恰恰最怕停顿; - 堆上限建议按“最大单次报表所需内存 × 1.5”估算,而非服务器总内存的1/4。例如实测导出10万行Excel需1.2GB堆,则设
-Xmx1800m更稳妥; - 32位JVM禁用,64位环境下堆可设到4G~8G,但需同步检查非堆内存是否够用(见下文);
- 不要把堆设到超过物理内存的75%,否则系统Swap频繁,反而拖慢报表导出速度。
配套调整新生代与GC策略(报表场景专用)
大报表产生大量短期对象(如单元格、样式、临时集合),若新生代太小,会频繁Minor GC并提前晋升老年代,加剧老年代压力。
- 用
-Xmn显式设置新生代,推荐为堆的1/3~1/2。例如堆2G,设-Xmn768m; - 搭配使用G1垃圾收集器:
-XX:+UseG1GC。它能预测停顿时间,适合报表这种“短时高压”场景; - 加
-XX:MaxGCPauseMillis=200控制单次GC停顿不超过200ms,避免用户感知卡顿; - 禁用CMS(已废弃),避免在Java 9+上启动失败。
必须同步限制元空间和线程栈(防“连带OOM”)
只调堆不管其他区域,报表期间仍可能报 OutOfMemoryError: Metaspace 或 unable to create new native thread:
- 报表常动态加载模板引擎(如JasperReports)、POI类、字体等,易撑爆元空间。加参数:
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m; - 每个导出请求开独立线程(尤其用异步Servlet或线程池时),默认线程栈(-Xss1M)会快速耗尽内存。设为
-Xss256k,既保安全又省空间; - 若用自定义线程池,务必限制最大线程数(如
maxPoolSize=10),避免无节制创建线程。
验证与上线前必做三件事
参数生效≠问题解决,必须实测验证:
- 启动后执行
jstat -gc <pid></pid>,确认初始堆(S0C/S1C/EC/OC)与配置一致,且没有频繁GC; - 模拟真实报表请求,用
jmap -histo:live <pid></pid>查看堆中Top对象,确认无意外大集合或未关闭流(如未close的Workbook); - 导出最大数据量报表时,观察
catalina.out是否有GC日志警告(如“to-space exhausted”),有则需调大-Xmn或-Xmx。











