对象有的存在在栈中
年轻代(伊甸园 s1,s0(8:1:1))fnedai
- 对象流转过程:
- 新对象在 Eden 区创建。
- Eden 区满时触发Minor GC(新生代垃圾回收),存活的对象被移至 Survivor 区(如 S0)。
- 下次 Minor GC 时,Eden 区和 S0 区存活的对象被移至 S1 区,S0 区清空。
- 多次 GC 后仍存活的对象(年龄达到阈值,默认 15 次)被移至老年代。
避免内存碎片
老年代:
- 触发 GC 条件:老年代空间不足时触发Major GC/Full GC(全局垃圾回收)。
特殊情况(栈上分配):
逃逸:对象的生命周期完全在方法内部,不会被外部访问。
- 在某些语言或优化场景下,短期存活的小对象可能被分配到栈上(如 Java 的逃逸分析优化)。
- 逃逸分析通过识别对象的生命周期范围,将不逃逸的短期小对象分配到栈上,避免 GC 开销,提升性能。
永久代:因为容易发生oom所以移动至方法区的元空间中
为什么大部分对象在堆中?
- 生命周期灵活性:堆内存允许对象在方法调用结束后继续存在(如返回对象引用)。
- 共享访问:多个线程可以访问同一对象(需注意线程安全)。
- 动态内存分配:适合创建大小不确定或需要长期存在的对象。
gc
垃圾回收机制(GC)
1. 垃圾回收算法
- 标记 - 清除(Mark-Sweep):
标记存活对象 → 清除未标记对象。缺点:产生内存碎片。 - 标记 - 整理(Mark-Compact):
标记存活对象 → 将对象移动到一端 → 清除边界外的内存。避免碎片,但需移动对象,成本高。 - 复制(Copying):
将内存分为两块,每次只使用一块。GC 时将存活对象复制到另一块,清空原区域。适用于对象存活率低的场景(如新生代)。 - 分代收集(Generational Collection):
根据对象生命周期不同,在新生代和老年代采用不同算法(如新生代用复制算法,老年代用标记 - 整理)。 - 新生代:复制算法
- 老年代:标记清除、标记整理
2. 常见垃圾回收器
新生代回收器:
- Serial:单线程,暂停所有用户线程(Stop The World,STW),适合单 CPU 环境。
- ParNew:Serial 的多线程版本,与 CMS 配合使用。
- Parallel Scavenge(吞吐量优先):多线程,目标是最大化吞吐量(CPU 用于运行用户代码的时间比例)。
- 老年代回收器:
- Serial Old:单线程,标记 - 整理算法。
- Parallel Old:Parallel Scavenge 的老年代版本,多线程标记 - 整理。
- CMS(Concurrent Mark Sweep):以获取最短回收停顿时间为目标,并发标记和清除,但会产生内存碎片。
- G1(Garbage-First):分 Region 管理内存,兼顾吞吐量和低延迟,适合大内存场景。
- ZGC(Z Garbage Collector):极低延迟(亚毫秒级),支持 TB 级内存,JDK 11 + 引入。
- 全区域回收器:
- Shenandoah:与 G1 类似,但更注重低延迟,通过并发整理减少 STW 时间。
- Epsilon:实验性回收器,仅分配内存,不执行垃圾回收(用于性能测试)。