JVM内存调优核心是理解区域职责与瓶颈对应关系:堆(-Xms=-Xmx)防动态扩容引发Full GC,元空间(-XX:MetaspaceSize/-XX:MaxMetaspaceSize)防类加载抖动,栈(-Xss)需权衡线程数与递归深度,新生代参数需联动优化以减少对象过早晋升。

记住JVM内存参数不靠死背,而靠理解区域职责和常见瓶颈。堆、元空间、栈这三块最常调,每块对应一类典型问题:对象分配慢或GC频繁 → 看堆;类加载报错或启动卡顿 → 看元空间;线程创建失败或栈溢出 → 看栈。参数不是孤立的,它们彼此制约,比如新生代设大了,老年代就小了,得通盘考虑。
堆内存:-Xms 和 -Xmx 必须相等
这是线上稳定性的底线。JVM启动后若堆需要动态扩容,会触发一次Full GC,停顿时间不可控。尤其在流量突增时,扩容叠加GC极易雪崩。所以生产环境一律设成相同值,例如 -Xms4g -Xmx4g。物理内存为8GB的机器,堆最多配到5~6GB,留足系统和其他进程空间。
- 堆大小建议占物理内存的50%~70%,超了容易引发系统OOM
- 用 jstat -gc <pid> 观察YGC频率和堆使用率,持续高于75%就要考虑扩容或优化对象生命周期
- 如果应用对象存活期短(如HTTP接口),新生代可设为堆的1/2;若缓存多、对象长期存活,新生代可压到1/3
元空间:-XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 要配对设
JDK 8+ 用元空间替代永久代,底层用本地内存,但不设限等于埋雷。Spring Boot这类大量动态生成类的框架,启动时若元空间反复扩容,就会频繁触发Full GC。默认初始值仅约21MB,远远不够。
- 推荐统一设为 -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m,既防启动抖动,又留出增长余量
- 若应用使用大量反射、字节码增强(如MyBatis Plus、Lombok),可上探至1GB
- 监控 MetaspaceUsed 指标,长期接近Max值,就要查是否有类加载泄漏(比如ClassLoader未释放)
新生代细节:-Xmn、-XX:SurvivorRatio、-XX:MaxTenuringThreshold
新生代是Minor GC主战场,调优目标是让大部分对象在Eden区“自然死亡”,少进Survivor,更少晋升老年代。三个参数要联动看:
- -Xmn 决定新生代总容量,设太小会导致对象频繁晋升,老年代快速填满;设太大则老年代吃紧,Major GC风险上升
- -XX:SurvivorRatio=6 比默认的8更合理——Eden:S0:S1 = 6:1:1,增大Survivor区能多撑几轮GC,减少早晋升
- -XX:MaxTenuringThreshold=6 适合Web类应用:多数请求对象活不过6次GC,设低些可避免“假长命”对象滞留Survivor
栈与线程:-Xss 不是越大越好
每个线程独占一块虚拟机栈,-Xss决定单个线程可用栈空间。设高了,单个线程稳健,但总线程数上限会骤降;设低了,深递归或复杂表达式易抛 StackOverflowError。
- 常规Web服务用 -Xss256k 或 -Xss512k 足够,比默认1MB更节省资源
- 若应用大量使用异步回调或深度嵌套调用,可试升到1M,但务必同步压测线程池承载力
- 注意:线程总数 = 可用内存 ÷ (-Xss值),别让 -Xss 成为并发瓶颈

















