Skip to content

JVM如何判断对象已死?

约 1206 字大约 4 分钟

Java

2025-05-30

一、JVM如何判断对象已死?

堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断哪些对象已经死亡(即不能再被任何途径使用的对象)。

1.1 引用计数法

给对象添加一个引用计数器,每当一个地方引用它object时技术加1,引用失去以后就减1,计数为0说明不再引用。

优点:实现简单,判定效率高;

缺点:无法解决对象相互循环引用的问题,对象A中引用了对象B,对象B中引用对象A。对应代码如下:

public class A {
    public B b; 
}
public class B {
    public C c; 
}
public class C {
    public A a; 
}
public class Test{

    private void test(){
        A a = new A();
        B b = new B();
        C c = new C();

        a.b=b;
        b.c=c;
        c.a=a;
    }
}

1.2 可达性分析

这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的,需要被回收。

那么,所谓的**“GC Roots”**指的是什么呢?

  • 虚拟机栈(栈帧中的局部变量表)中引用的对象
  • 本地方法栈(Native 方法)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 所有被同步锁持有的对象
  • JNI(Java Native Interface)引用的对象
详情

复习Java的运行时内存

线程私有:虚拟机栈、本地方法栈、程序计数器

线程共有: 堆(还包含一个字符串常量池)、方法区

二、Java的四种引用类型

无论是通过引用计数法判断对象引用数量,还是通过可达性分析判断对象的引用链是否可达,判定对象的存活都与“引用”有关。

那么,这个所谓的“引用”又是什么东西?

现在Java将引用分为强引用、软引用、弱引用、虚引用四种(引用强度逐渐减弱),强引用就是 Java 中普通的对象,而软引用、弱引用、虚引用在 JDK 中定义的类分别是 SoftReferenceWeakReferencePhantomReference

2.1 强引用

强引用实际上就是程序代码中普遍存在的引用赋值,这是使用最普遍的引用,例如以下代码:

//强引用示例
String strongReference = new String("abc");
String strongReference2 = "abc";
详情

两种创建字符串的方式:

String strongReference = "abc";

  • 这种方式是通过字符串常量池来创建字符串对象的。
  • 当你使用双引号定义字符串时,Java会先检查字符串常量池中是否已经存在一个值

String strongReference = new String("abc");

  • 这种方式是通过new关键字创建字符串对象的。
  • 每次调用new String("abc")都会在堆内存中创建一个新的字符串对象,即使字符串的内容相同。

这两种方式都是产生的强引用

如果一个对象具有强引用,那么垃圾回收器绝不会回收它。当内存空间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题

2.2 软引用

软引用允许垃圾收集器在内存不足时回收被软引用指向的对象,可以通过以下方式来创建:

// 软引用
String str = new String("abc");
SoftReference<String> softReference = new SoftReference<String>(str);

如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。

软引用可用来实现内存敏感的高速缓存,当内存不足时,可以自动释放缓存对象。

2.3 弱引用

只具有弱引用的对象拥有更短暂的生命周期。

在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

2.4 虚引用

虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

虚引用主要用来跟踪对象被垃圾回收的活动。但是实际开发中用的也比较少,用的最多的还是软引用