10. 垃圾回收的算法
1. 垃圾回收
垃圾回收(Garbage Collection, GC)是一种自动内存管理机制,由程序(通常是运行时环境或虚拟机)自动检测和回收不再使用的内存对象,从而避免内存泄漏,减少程序员手动管理内存的负担。
为什么需要垃圾回收?
手动内存管理的痛点:
C/C++ 中需手动
malloc/free
或new/delete
,易出错:内存泄漏:忘记释放内存。
悬垂指针:释放后仍被引用。
重复释放:导致程序崩溃。
自动GC的优势:
减少程序员负担,提高开发效率。
避免内存泄漏和部分内存错误。
垃圾回收的典型过程
标记(Mark)
通过可达性分析,标记所有存活对象。
回收(Reclaim)
根据不同算法(如清除、复制、整理)回收垃圾内存。
压缩(可选,Compact)
整理内存碎片,提高后续分配效率。
垃圾回收的触发时机
主动触发:当内存不足时(如Java的
OutOfMemoryError
前)。被动触发:定时或分代策略(如新生代满时触发Minor GC)。
哪些语言/环境依赖GC?
完全依赖:Java(JVM)、Python、Go、C#(.NET)、JavaScript(V8引擎)。
可选GC:Rust(需手动管理,但有第三方GC库)、Swift(ARC自动引用计数)。
无GC:C、C++(需手动管理)。
GC与内存泄漏
即使有GC,仍可能发生内存泄漏,例如:
无意识的对象保留(如全局集合未清理)。
长生命周期对象持有短生命周期对象的引用(如缓存未过期)。
非内存资源未释放(如文件句柄、数据库连接)。
GC的优缺点
优点 | 缺点 |
---|---|
避免内存泄漏和悬垂指针 | 占用额外CPU/内存资源 |
简化开发,提高安全性 | 不可预测的停顿(Stop-The-World) |
适合高抽象层级语言(如Java) | 难以处理实时性要求高的场景 |
垃圾回收是自动管理内存生命周期的技术,通过标记-清除、复制、分代等算法平衡内存效率和程序性能。它的存在让开发者更专注于业务逻辑,但需理解其原理以优化应用表现(如调整JVM参数)。
2. 常用的垃圾回收算法
- 标记清除算法
- 复制算法
- 标记整理算法
- 分代收集算法
1. 标记-清除算法(Mark-Sweep)
步骤:
标记:从根对象(如全局变量、栈变量)出发,遍历所有可达对象并标记为“存活”。
清除:扫描堆内存,回收未被标记的垃圾对象内存。
优点:简单直接,处理循环引用无压力。
缺点:产生内存碎片,分配效率下降;两次遍历(标记+清除)导致停顿时间较长。
2. 复制算法(Copying)
步骤:
将堆分为From和To两个等大空间。
将存活对象从From复制到To,并紧凑排列。
清空From,交换From和To的角色。
优点:无内存碎片,分配高效(指针碰撞)。
缺点:浪费一半内存空间;复制大对象开销大。
应用场景:Java新生代的Serial、ParNew等回收器。
3. 标记-整理算法(Mark-Compact)
步骤:
标记:同标记-清除。
整理:将存活对象向内存一端移动,消除碎片。
优点:无碎片,适合老年代。
缺点:移动对象成本高,停顿时间长。
应用场景:Java的CMS、G1回收器的老年代阶段。
4. 分代收集算法(Generational)
核心思想:根据对象存活周期划分内存区域(如新生代、老年代),对不同区域采用不同算法。
新生代:频繁回收,使用复制算法(如Java的Eden+Survivor区)。
老年代:较少回收,使用标记-清除或标记-整理。
优点:结合场景优化效率,减少全局停顿。
缺点:需处理跨代引用问题。
咱们后面说====================================================>
3. 问题总结
3.1 JVM 垃圾回收算法有哪些?
- 标记清除算法:垃圾回收分为2个阶段,分别是标记和清除,效率高,有磁盘碎片,内存不连续。
- 标记整理算法:标记清除算法一样,将存活对象都向内存另一端移动,然后清理边界以外的垃圾,无碎片,对象需要移动,效率低。
- 复制算法:将原有的内存空间一分为二,每次只用其中的一块,正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收;无碎片,内存使用率低。
上一篇 下一篇