58. Java 类和对象 - 垃圾回收器

74 阅读4分钟

58. Java 类和对象 - 垃圾回收器

🌿 引言

大家好!今天学习 Java 垃圾回收器 (Garbage Collector, GC)! 今天,我们要一起探讨 Java 是如何自动管理内存的,以及为什么垃圾回收机制是 Java 语言的一大亮点。

我们会围绕以下几个方面展开:

  1. 什么是垃圾回收器?
  2. 显式内存管理 vs. 自动垃圾回收
  3. 对象何时符合垃圾回收条件?
  4. 多引用的影响
  5. 垃圾回收器的工作机制
  6. 示例讲解

大家准备好了吗?那我们正式开始!🚀


🌱 1. 什么是垃圾回收器?

在某些面向对象语言中,比如 C++,我们需要手动跟踪对象,并在不需要时明确销毁它们,这种方式叫做 显式内存管理。 然而,这种方法有很大的风险:

  • 如果你忘了释放内存,会导致 内存泄漏
  • 如果释放了还继续访问对象,会引发 空指针异常 等问题。

而 Java 提供了一种更安全和高效的方式:自动垃圾回收机制

垃圾回收器 (Garbage Collector, GC) 是 Java 虚拟机 (JVM) 内置的工具。它会自动检测哪些对象不再被使用,并回收它们占用的内存。 换句话说,在 Java 中,你只需要专注于写代码,JVM 会帮你搞定大部分的内存管理工作!✨


⚔️ 2. 显式内存管理 vs. 自动垃圾回收

我们来快速对比一下:

特点显式内存管理 (如 C++)自动垃圾回收 (Java)
内存分配手动调用 new自动调用 new
内存释放使用 delete 释放对象JVM 自动回收无引用对象
错误风险内存泄漏、空指针异常内存泄漏风险降低
控制力精确控制对象何时销毁GC 自动决定回收时机
编程复杂度需要额外管理内存逻辑更简洁,无需手动释放内存

所以,Java 的自动垃圾回收让我们少踩很多内存管理的坑!✅


🏷️ 3. 对象何时符合垃圾回收条件?

Java 中,一个对象只有在 没有任何存活引用 时,才会被标记为 可回收对象

让我们看看几种常见情况:

🎯 情况1:引用超出作用域

当方法结束后,局部变量引用会失效:

public void example() {
    Point p = new Point(1, 2); // p在方法内有效
} // 方法结束后,p的引用消失,对象可回收

p 是一个局部变量,在方法执行完毕后就超出了作用域,因此与 Point 对象的关联被切断,Point 对象变成垃圾对象


🎯 情况2:显式设置为 null

你也可以手动断开引用:

Point p = new Point(1, 2);
p = null; // p不再指向对象,该对象可回收

这里我们将 p 设置为 null,意味着不再引用任何对象,原本的 Point 对象会被回收


🎯 情况3:引用被覆盖

当变量重新赋值时,原对象的引用会被覆盖:

Point p1 = new Point(1, 2);
Point p2 = p1; // p1 和 p2 指向同一个对象
p1 = new Point(3, 4); // p1 指向新对象
p2 = null; // 原对象无引用,可回收

这段代码中:

  1. p1p2 最开始指向同一个对象 Point(1, 2)
  2. p1 被重新赋值为 Point(3, 4) 后,p2 又被设为 null
  3. 此时,Point(1, 2) 对象已没有任何引用,成为垃圾对象。

🔗 4. 多个引用的影响

有时,一个对象可能会有多个引用:

Point p1 = new Point(1, 2);
Point p2 = p1; // 两个引用指向同一个对象
p1 = null;     // 只剩 p2 引用,对象不可回收
p2 = null;     // 无引用,对象可回收

注意!

  • p1 = null 时,对象不会被回收,因为 p2 还指向它;
  • 只有当 所有引用都断开 时,垃圾回收器才会考虑回收对象!

所以,即使一个对象失去了部分引用,也不代表它马上会被回收。


⚙️ 5. 垃圾回收器的工作机制

JavaGC 并不是随时都在运行,而是由 JVM 在合适的时机触发:

🌟 触发条件

  1. 内存不足时
  2. 系统空闲时
  3. 手动建议触发
System.gc(); // 建议 JVM 执行 GC

⚠️ 注意! System.gc() 只是建议JVM 可以选择忽略。垃圾回收的时机完全由 JVM 自己决定!


🚀 标记-清除算法

垃圾回收的常见算法是 标记-清除算法

  1. 标记阶段:从根对象 (比如栈帧变量、静态变量等) 出发,标记所有仍在使用的对象;
  2. 清除阶段:回收未被标记的对象,占用的内存被释放。

JVM 会使用 可达性分析算法 来判断对象是否存活,而不是简单地检查对象是不是 null