本文共 1265 字,大约阅读时间需要 4 分钟。
垃圾回收机制
1. 垃圾回收策略
1.1 对象存活判断
垃圾回收需要判断对象是否仍然存活,即是否有可达路径(Reachability)。主要有两种常用方法:
1.1.1 引用计数法
- Python 和 C++ 常用这种方法。
- 给每个对象附加一个引用计数器,引用增加计数器,释放时减少。
- 计数器为 0 的对象被标记为不在存活。
- 缺点:无法解决循环引用问题。
1.1.2 可达性分析算法
- Java 和 C# 使用。
- 核心思想:从 GC Roots 开始,沿着可达路径标记对象。
- 若路径断绝,则对象视为不存活。
1.2 GC Roots
- 包括:
- 虚拟机栈中的临时变量引用。
- 本地方法栈中的 JNI 引用。
- 方法区中的类静态变量引用。
- 方法区中的常量引用。
2. 引用扩充
JDK 1.2以后引入了四种引用的强度:
强引用:最常见的引用,覆盖许多日常对象。 软引用:用来缓存非必需对象,比如[LRU缓存]. 弱引用:对象在内存不足时会被回收。 虚引用:最弱的引用,无法阻止对象回收,但提供回收时的回调通知。 // 软引用示例SoftReference
3. 对象自我拯救
在 GC 开始回收时,如果对象不再可达,系统可能立即回收。但有些对象会自行拯救:
- calling
finalize():这是对象实现自救的唯一机会。 - 若
finalize() 未被调用或未能完成自救,对象将被回收。
public void finalize() throws Throwable { // 在这里进行自救操作 System.out.println("正在自救..."); referenceQueue.add(this);}
4. 方法区的回收
特点:
- 简单对象(如常量、静态变量)被回收。
- 回收频率低,主要处理废弃的类和不用的常量。
5. 堆的垃圾回收算法
5.1 标记-清除算法
- 样例:对新生代进行快速回收,但效率较低。
- 缺点:内存碎片较多。
5.2 复制算法
- 适用于新生代:
- 内存分为 Eden、From、To 三个区域。
- 不断复制存活对象到 From-To 区域,清理旧区。
- 长期存活的对象进入老年代。
5.3 标记-整理算法
- 专门处理老年代:
- 整理阶段将存活对象集中到一边,然后清理边界外的空间。
- 替代了传统的清除算法,减少了内存碎片。
5.4 分代收集策略
- 新生代使用复制算法,老年代使用标记-整理。
- 最新 Java GC 集线性处理算法提高效率。
Minor GC 与 Full GC
- Minor GC:主要处理新生代。
- Full GC:处理老年代,回收速度较慢。
通过以上策略,垃圾回收系统能够高效管理内存,平衡性能与节省内存空间。
转载地址:http://itlmz.baihongyu.com/