jvm如何判断对象是否可以被回收

本文介绍了Java虚拟机(JVM)中的垃圾回收机制,重点讲解了如何通过GCroots判断对象是否可达,进而决定对象是否可以被回收。文章还概述了虚拟机栈、方法区静态属性及本地方法栈作为GCroots的作用,并简要介绍了Java中的四种引用类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内容基本来自周志明 深入理解java虚拟机 第二版 第三章 。这本书还可以,不过好像也没什么其他中文的关于jvm比较好的书了

jvm要做垃圾回收时,首先要判断一个对象是否还有可能被使用。那么如何判断一个对象是否还有可能被用到?

如果我们的程序无法再引用到该对象,那么这个对象就肯定可以被回收,这个状态称为不可达。当对象不可达,该对象就可以作为回收对象被垃圾回收器回收。

那么这个可达还是不可达如何判断呢?

答案就是GC roots ,也就是根对象,如果从一个对象没有到达根对象的路径,或者说从根对象开始无法引用到该对象,该对象就是不可达的。

以下三类对象在jvm中作为GC roots,来判断一个对象是否可以被回收
(通常来说我们只要知道虚拟机栈和静态引用就够了)

  • 虚拟机栈(JVM stack)中引用的对象(准确的说是虚拟机栈中的栈帧(frames))
    我们知道,每个方法执行的时候,jvm都会创建一个相应的栈帧(栈帧中包括操作数栈、局部变量表、运行时常量池的引用),栈帧中包含这在方法内部使用的所有对象的引用(当然还有其他的基本类型数据),当方法执行完后,该栈帧会从虚拟机栈中弹出,这样一来,临时创建的对象的引用也就不存在了,或者说没有任何gc roots指向这些临时对象,这些对象在下一次GC时便会被回收掉

  • 方法区中类静态属性引用的对象
    静态属性是该类型(class)的属性,不单独属于任何实例,因此该属性自然会作为gc roots。只要这个class存在,该引用指向的对象也会一直存在。class 也是会被回收的,在面后说明

  • 本地方法栈(Native Stack)引用的对象

一个class要被回收准确的说应该是卸载,必须同时满足以下三个条件

  • 堆中不存在该类的任何实例
  • 加载该类的classloader已经被回收
  • 该类的java.lang.Class对象没有在任何地方被引用,也就是说无法通过反射再带访问该类的信息

这篇内容太少了,在说几句java中的四种引用类型

其实这四类引用的区别就在于GC时是否回收该对象

  • 强引用(Strong) 就是我们平时使用的方式 A a = new A();强引用的对象是不会被回收的
  • 软引用(Soft) 在jvm要内存溢出(OOM)时,会回收软引用的对象,释放更多内存
  • 弱引用(Weak) 在下次GC时,弱引用的对象是一定会被回收的
  • 虚引用(Phantom) 对对象的存在时间没有任何影响,也无法引用对象实力,唯一的作用就是在该对象被回收时收到一个系统通知
### JVM 垃圾回收判断对象回收性的机制 JVM 的垃圾回收器通过一系列算法和条件来判断对象是否可以被回收。这些条件通常基于对象的引用状态以及其在内存中的存活情况。 #### 引用计数法 一种简单的判断对象是否回收的方式是 **引用计数法**,即为每个对象维护一个引用计数器。当有一个新的引用指向该对象时,计数加一;当某个引用失效时,计数减一。如果计数值降为零,则表示没有任何引用指向此对象,因此它被认为是可回收的[^3]。 然而,这种方法存在循环引用的问题,可能导致某些实际上已经不再使用的对象无法被正确回收。 #### 可达性分析算法 为了克服引用计数法的缺陷,现代 JVM 主要采用 **可达性分析算法**(Reachability Analysis)。这种算法从一组称为“GC Roots”的根节点集合出发,沿着引用链向下搜索所有可达的对象。任何未被引用链触及到的对象都被视为不可达,从而成为候选回收目标[^1]。 常见的 GC Root 类型包括但不限于: - 虚拟机栈中局部变量表内的引用; - 方法区中类静态属性所持有的引用; - 方法区中常量池里的引用; - 本地方法栈中 JNI 所持的引用。 一旦确认某对象不可达,进一步还需要验证是否有其他特殊原因阻止它的立即销毁,比如 finalize() 方法的存在与否及其执行结果可能影响最终决定。 #### 不同类型的引用对回收的影响 除了基本的强引用外,Java 还定义了几种特殊的弱软虚引用形式,它们各自对应着不同强度级别的关联关系,并间接决定了何时适合触发相应的清理动作: - **Soft Reference**: 在内存不足之前不会轻易丢弃此类数据项。 - **Weak Reference**: 即使还有少量可用空间也会尽快处理掉这类实例。 - **Phantom Reference**: 更倾向于配合特定事件通知机制而非直接参与常规意义上的资源管理流程之中。 综上所述,JVM 使用多种技术和手段综合评估哪些对象应该进入下一轮清扫范围之内并实际实施操作过程。 ```java // 示例代码展示如何创建不同类型引用 import java.lang.ref.*; public class RefDemo { public static void main(String[] args) throws InterruptedException { Object obj = new Object(); // 创建一个新对象 SoftReference<Object> softRef = new SoftReference<>(obj); WeakReference<Object> weakRef = new WeakReference<>(obj); PhantomReference<Object> phantomRef = new PhantomReference<>(obj, null); obj = null; // 断开原始强引用 System.out.println(softRef.get()); // 输出可能是null或者原对象 System.out.println(weakRef.get()); // 很大概率已经是null System.out.println(phantomRef.get());// 总返回null } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值