应先用ps -ef | grep java | grep -E 'Xmx|Xms'查各Java进程真实堆配置,再按负载分档设置-Xms/-Xmx及-XX:MaxMetaspaceSize,禁用已废弃的-XX:MaxPermSize,并优雅重启。

直接看进程实际堆配置,别信默认值
OpenJDK 启动时默认按物理内存的 1/4 设 -Xmx,一台 16GB 内存的机器,单个 JVM 就可能默认占 4GB。5 个 Java 进程全开,默认就吃掉 20GB——早超了。所以第一步永远是查真实配置:
ps -ef | grep java | grep -E 'Xmx|Xms'重点看每个进程是否都带
-Xmx,数值加起来有没有超过物理内存(记得预留至少 2GB 给系统和内核)。如果没显式设置,就等于在裸奔。
Tomcat 多实例的堆分配必须差异化,不能一刀切
你有 5 个 Tomcat 实例(tomcat_+、tomcat1~tomcat4),但它们负载差异极大:
-
tomcat1配了-Xms256m -Xmx4000m:堆初始太小,启动后疯狂扩容;-XX:MaxPermSize=4000m在 OpenJDK 17+ 完全无效(已被-XX:MaxMetaspaceSize取代),元空间实际失控 -
tomcat2/3/4全是-Xms256m -Xmx512m:Spring Boot 应用跑起来不到 1 分钟就java.lang.OutOfMemoryError: Metaspace -
tomcat_+虽然配了-Xmx2048m,但得确认它是不是真承载核心业务——否则就是资源错配
- 主业务实例(如网关、订单):固定堆
-Xms2g -Xmx2g,加-XX:MaxMetaspaceSize=512m - 轻量管理后台或定时任务:设
-Xms512m -Xmx1g,-XX:MaxMetaspaceSize=256m - 所有实例统一禁用
-XX:MaxPermSize(JDK 8u212+、OpenJDK 9+ 已废弃)
OpenJDK 17+ 必须管住元空间,否则堆再小也爆
元空间(Metaspace)不在堆里,但同样吃物理内存。它存类定义、方法元数据,Spring Boot 加载几百个 Bean 后很容易冲到 1GB+。OpenJDK 17 默认不限制元空间大小,只受系统内存限制——这就是为什么 tomcat1 明明堆只设了 4GB,free -h 却显示内存 99%。关键控制参数只有两个:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
-
-XX:MetaspaceSize=256m:触发首次元空间 GC 的阈值(不是初始大小) -
-XX:MaxMetaspaceSize=512m:硬上限,超了直接 OOM,不给机会乱涨
-XX:MaxMetaspaceSize 是生产环境最常踩的坑,比堆配错还隐蔽。
重启前先 kill -15,别一上来就 kill -9
改完 -Xmx 和 -XX:MaxMetaspaceSize 后,必须优雅重启才能生效。直接 kill -9 会跳过 JVM 的 shutdown hook,导致临时文件、连接池、JMX 注册残留,下次启动可能抢不到端口或连不上数据库。正确顺序:
- 用
ps -ef | grep tomcat找出 PID - 发
kill -15 <pid></pid>,等 10 秒 - 检查
ps -p <pid></pid>是否退出;没退再kill -9 - 启动时加
-XX:+PrintGCDetails确认新参数已加载
真正难的不是算数,而是搞清每个 Java 进程到底在干什么——配置写在脚本里,但负载藏在日志和监控里。没摸清业务流量模式之前,所有内存数字都是纸面假设。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










