Java中的JVM内存分配与回收策略详解
字数 1203 2025-11-17 15:52:14
Java中的JVM内存分配与回收策略详解
一、内存分配的基本策略
- 对象优先在Eden区分配
- 新创建的对象通常会被分配在新生代的Eden区
- Eden区内存连续,分配速度快(指针碰撞或空闲列表)
- 示例:Object obj = new Object() 会在Eden区分配内存
- 大对象直接进入老年代
- 需要大量连续内存的对象(如长数组、大字符串)
- 避免在Eden区和两个Survivor区之间大量复制
- 通过-XX:PretenureSizeThreshold参数设置阈值
二、内存分配的具体过程
-
正常情况下的分配流程:
a. 尝试在Eden区分配内存
b. 如果Eden区空间不足,触发Minor GC
c. 存活对象复制到Survivor区(From/To空间)
d. 对象年龄增加到阈值(默认15)时晋升老年代 -
空间分配担保机制:
a. Minor GC前检查老年代最大可用空间
b. 如果大于新生代所有对象总大小,确保安全
c. 否则检查-XX:HandlePromotionFailure设置
d. 允许担保失败时重新发起Full GC
三、对象晋升老年代的条件
- 年龄阈值机制
- 对象每在Survivor区经历一次Minor GC,年龄加1
- 当年龄超过-XX:MaxTenuringThreshold(默认15)时晋升
- 动态年龄判定
- 如果Survivor区中相同年龄所有对象大小超过Survivor空间一半
- 年龄大于等于该年龄的对象直接进入老年代
- 分配担保失败
- Survivor区无法容纳Minor GC后的存活对象时
- 通过分配担保机制直接进入老年代
四、内存回收策略详解
- Minor GC(年轻代回收)
- 触发条件:Eden区空间不足
- 采用复制算法:Eden区存活对象→Survivor区
- Stop-the-World时间较短
- Full GC(整堆回收)
- 触发条件:老年代空间不足/空间分配担保失败
- 回收整个堆和方法区
- Stop-the-World时间较长
五、相关JVM参数调优
- -XX:PretenureSizeThreshold:大对象直接进入老年代的阈值
- -XX:MaxTenuringThreshold:对象晋升老年代的年龄阈值
- -XX:TargetSurvivorRatio:Survivor区的目标使用率
- -XX:+UseAdaptiveSizePolicy:开启自适应内存分配策略
六、实际应用示例
假设JVM参数配置:-Xms20m -Xmx20m -XX:SurvivorRatio=8
- 新生代总空间:20MB × 1/3 ≈ 6.67MB
- Eden区:6.67MB × 8/10 ≈ 5.3MB
- 每个Survivor区:约0.67MB
- 当创建多个2MB数组时,会根据策略选择在Eden区分配或直接进入老年代
这种内存分配策略平衡了内存使用效率和GC性能,是JVM性能调优的重要基础。