大对象直接进入老年代是硬性路径而非可选优化,前提是对象大小≥PretenureSizeThreshold且超过Eden最大连续空闲块;该机制仅在Serial/Parallel GC下生效,G1/ZGC/Shenandoah不支持。

大对象直接进老年代,不是“可选优化”,而是内存分配流中一条有明确物理边界的硬性路径。它绕过Eden和Survivor的唯一前提,是JVM在分配前就判定:该对象无法被新生代任何连续空闲块容纳——这个判断发生在指针碰撞(或TLAB填充)的毫秒级瞬间,且结果不可回退。
触发的物理前提:连续空间 + 阈值双校验
JVM分配一个对象时,先静态估算其大小(含对象头、实例字段、对齐填充),再检查是否满足两个并列条件:
- 对象估算大小 ≥ -XX:PretenureSizeThreshold 设置值(默认为0,即不启用)
- 该大小 > 当前Eden区剩余最大连续空闲块(注意:不是剩余总空间,而是最大连续段)
二者必须同时成立。例如Eden还剩3MB碎片化空间(两段1MB+一段1MB),但对象需2.5MB连续空间,即便PretenureSizeThreshold设为2MB,仍会触发直接入老年代;反之,若对象仅1.8MB,则不触发。
收集器依赖:Parallel与Serial才认这个参数
该机制并非JVM通用能力,而是特定于分代复制式GC的工程妥协:
- 有效场景:-XX:+UseParallelGC 或 -XX:+UseSerialGC 启用时,PretenureSizeThreshold才起作用
- 无效场景:G1使用Humongous Region机制,ZGC/Shenandoah无分代概念,它们根本不读取该参数
- 配置孤立无效:只设-XX:PretenureSizeThreshold却不配对应GC,等于没设
老年代承接失败的物理后果
跳过新生代不等于免检老年代——对象仍需在老年代找到一块连续空间:
- 若老年代剩余最大连续块
- Full GC后仍不满足 → 抛出 java.lang.OutOfMemoryError: Java heap space(不是Metaspace或Stack)
- 日志特征明显:GC log中出现 "allocation failure"未伴随PSYoungGen回收记录,且紧接老年代使用率飙升或Full GC标记
真实大小判定:别信字段数,要算布局宽度
所谓“大”,由JVM编译期确定的对象内存布局决定,而非运行时内容:
- 数组对象大小 = 对象头(12B) + length字段(4B) + 元素数据区(如byte[1024*1024] → 1MB纯数据)
- String对象本身不大(含char[]引用),但new String(new char[1000000])会因底层数组被识别为大对象
- 引用类型字段只计引用宽度(4B或8B),不计所指对象大小
- 验证工具推荐:jol-cli 查 object layout,比代码估算可靠十倍

















