当JAVA垃圾收集器(GC)运行时,它作为一个守护线程在后台运行,用于为用户线程提供服务或执行JVM任务 。它定期检查堆内存中的所有对象 , 并识别那些不再被程序的任何部分引用的对象(也就是不再被引用的对象) 。然后 , 这些不再被引用的对象将被销毁,并释放空间供新创建的对象使用 。
以下是Java垃圾收集过程的简单步骤:
1.标记(Mark):从GC根开始,识别当前正在使用和未使用的对象引用 , 未使用的对象被标记为垃圾 。2.清除(Sweep):遍历堆,并找到存活对象之间的未使用空间,将这些空间记录在一个空闲列表中,供将来的对象分配使用 。3.压缩(Compact):将所有存活的对象移动到一个连续的内存区域中 , 以提高新对象的内存分配性能 。
然而 , 这种方法存在一些问题:
•效率低下,因为大多数新创建的对象很快就会变得无用 。•长寿命对象很可能在将来的GC周期中仍然被使用 。
为了解决这些问题,实际上,新创建的对象会根据其存活时间存储在堆的不同代空间中 。然后 , 在执行完整的垃圾收集之前,垃圾收集会在两个主要阶段进行,称为Minor GC(年轻代垃圾收集)和Major GC(老年代垃圾收集),对象会在这些代之间进行扫描和移动 。下图展示了堆内存的这种划分:
JVM堆内存
标记-清除模型标记-清除模型是Java垃圾收集的基本实现 。它有两个主要阶段:
1.标记(Mark):从GC根开始,识别并标记所有仍然被引用的对象,其余的被认为是垃圾 。2.清除(Sweep):遍历堆,并找到存活对象之间的未使用空间,将这些空间记录在一个空闲列表中 , 供将来的对象分配使用 。
Java垃圾收集的根现在你知道了,当没有引用指向一个对象时,它变得不可访问,因此也成为垃圾收集的候选对象 。等等,这是什么意思?引用是指什么?那么第一个引用是什么?我最初也有同样的问题 。让我解释一下这些引用和可达性在底层是如何发生的 。
为了让你的应用程序代码能够访问一个对象,必须存在一个根对象,它与你的对象相连,并且能够从堆外部访问 。这些从堆外部可以访问的根对象称为垃圾收集(GC)根 。垃圾收集根有几种类型,比如局部变量、活动的Java线程、静态变量、JNI引用等(只是了解这里的思想 , 如果你进行快速的谷歌搜索,可能会找到许多关于GC根的不一致的分类) 。我们需要学习的是,只要我们的对象被这些GC根之一直接或间接引用,并且GC根保持活动状态,我们的对象就可以被认为是可达的 。一旦我们的对象失去与GC根的引用 , 它就变得不可达,因此可以进行垃圾收集 。
可达性与垃圾收集的资格垃圾收集器只会销毁不可达的对象 。它是在后台自动进行的过程,一般情况下 , 程序员不需要对此做任何操作 。
注意:在销毁对象之前,垃圾收集器最多会在该对象上调用一次考虑下面的finalize()
方法(finalize()
方法不会对任何给定的对象多次调用) 。默认的finalize()
方法为空实现 。通过重写它,我们可以执行一些清理活动 , 比如关闭数据库连接或验证对象的结束,就像我下面写的那样 。一旦finalize()
方法完成,垃圾收集器将销毁该对象 。
Person
类 , 它有一个对象构造函数和finalize()
方法:class Person {
// 存储人员(对象)的名称
String name;
public Person(String name) {
this.name = name;
}
@Override
/* 重写finalize方法,以检查哪个对象被垃圾收集 */
protected void finalize() throws Throwable {
// 将打印出人员(对象)的名称
System.out.println("Person对象 - " + this.name + " -> 成功被垃圾收集");
}
}
如果满足以下任一情况,对象可以立即变为不可达(无需等待堆中的分代老化) 。情况1:将引用变量置为null当一个对象的引用变量被改为
null
时 , 该对象变得不可达,从而可以进行垃圾收集 。// 创建一个Person对象
推荐阅读
- Java 21,虚拟线程、结构化并发和作用域值
- 四个鲜为人知的Python迭代过滤函数
- 五个帮助初学者提高编码技术的简单方法
- AI绘画 | 纯净美丽的白色薄纱少女
- “维护者都快累死了!”Linux 宣布:LTS 版本的维护期,将从 6 年变回 2 年
- 深度学习的关键特征是什么
- 解决梯度消失问题的神经网络结构及其广泛应用
- AI绘画 | 黑发及腰的魅力少女
- 深度网络的退化问题
- 数字人点燃杭州亚运会主火炬!亚运史首个!到底是如何实现的?