在 Java HotSpot JVM 中,“大对象”并不是由单一固定字节数定义的,而是取决于垃圾收集器类型、堆内存布局和 JVM 参数。核心判断标准是:对象所需连续内存是否超过某个阈值,导致分配和回收策略与普通对象不同。
一、什么是大对象?
大对象通常指:
占用连续内存很大的对象(如大数组
byte[]、int[]、大型缓存对象)。分配成本高:在新生代频繁复制代价大,因此往往直接进入老年代。
回收代价高:可能触发 Full GC 或影响停顿时间。
二、不同 GC 下的大对象标准
1. G1 GC(主流,Java 8+ 默认)
在 G1(Garbage-First) 中:
堆被划分为多个 Region(1MB~32MB,启动时确定)。
大对象(Humongous Object):
👉 单个对象大小 > Region 大小的 50%
📌 特点:
大对象直接分配到 Humongous Regions(属于老年代)。
大对象不会被移动,回收时只能靠 Full GC 或 Mixed GC。
过多大对象会显著增加 GC 停顿。
2. Parallel / CMS GC(传统 GC)
在 Parallel Scavenge / CMS 中:
没有“Region”概念。
使用参数:
-XX:PretenureSizeThreshold=<字节数>超过该阈值的对象直接在老年代分配。
示例:
-XX:PretenureSizeThreshold=10m
表示 > 10MB 的对象是大对象。
⚠️ 默认值通常是 0(表示不启用),由 JVM 自行决定。
3. ZGC / Shenandoah(低延迟 GC)
没有传统意义上的“大对象”概念。
支持 TB 级堆,对象分配策略不同。
但仍建议避免超大对象,以减少内存碎片和停顿。
三、如何判断你的 JVM 中大对象阈值?
✅ 查看 G1 Region 大小
java -XX:+PrintGCDetails -version
或运行时通过:
jcmd <pid> VM.flags
✅ 查看 PretenureSizeThreshold
java -XX:+PrintFlagsFinal -version | grep PretenureSizeThreshold
四、实际开发中的经验值(参考)
五、为什么大对象要特别小心?
🐢 分配慢:需要找连续内存
🔁 复制成本高
⏱️ 更容易触发 Full GC
🧩 容易造成内存碎片
六、一句话总结
在 Java 中,大对象是“大到影响 GC 行为”的对象;在 G1 中是超过 Region 一半的对象,在 CMS/Parallel 中由 -XX:PretenureSizeThreshold决定,通常几 MB 就可能被视为大对象。