本文介绍: 引用计数法是一种简单而直观的垃圾收集算法,其核心思想是通过在对象头中添加一个引用计数器,记录对象引用的次数。GC Roots包括虚拟机栈中引用对象方法区中类静态属性引用对象方法区中常量引用对象以及本地方法栈中JNI(Java Native Interface)引用对象。例如,两个对象互相引用,它们的引用计数永远不会变为零,即使它们已经不再被程序使用。强引用是最常见的引用类型,只要强引用存在,垃圾收集器就不会回收被引用的对象。通过标记可达的对象,然后清除不可达的对象,最终回收被标记的垃圾

目录

垃圾的条件

1、引用计数法

2、可达性分析

3、强引用

4、软引用

5、弱引用

6、虚引用


判断垃圾条件

在Java虚拟机(JVM)中,垃圾收集器负责管理内存,其中的垃圾收集算法用于确定哪些对象是垃圾,可以被回收以释放内存空间。Java中主要使用的是自动内存管理,垃圾收集器会自动识别和回收不再被程序引用的对象。以下是一些判定对象为垃圾的条件:

1、引用计数

引用计数法是一种简单而直观的垃圾收集算法,其核心思想是通过在对象头中添加一个引用计数器,记录该对象被引用的次数。每当有一个新的引用指向该对象时,引用计数加一;当引用被删除或者超出作用范围时,引用计数减一。当引用计数为零时,表示该对象不再被引用,即可以被回收。

然而,引用计数法有一个明显的缺陷,即难以处理循环引用的情况。例如,两个对象互相引用,它们的引用计数永远不会变为零,即使它们已经不再被程序所使用。

以下是一个简单的引用计数法的Java代码示例

class ReferenceCountingObject {
    private int referenceCount = 0;

    public ReferenceCountingObject() {
        // 对象初始化时,引用计数为 0
    }

    public void addReference() {
        referenceCount++;
    }

    public void removeReference() {
        referenceCount--;
        if (referenceCount == 0) {
            // 当引用计数为零时,可以进行垃圾回收操作
            System.out.println("对象被回收");
        }
    }
}

public class ReferenceCountingExample {
    public static void main(String[] args) {
        // 创建两个对象
        ReferenceCountingObject obj1 = new ReferenceCountingObject();
        ReferenceCountingObject obj2 = new ReferenceCountingObject();

        // obj1 引用计数加一
        obj1.addReference();
        // obj2 引用计数加一
        obj2.addReference();

        // obj1 引用计数减一
        obj1.removeReference();

        // obj1 引用计数为零,可以进行垃圾回收
        // obj2 引用计数仍为一
    }
}

2、可达性分析

可达性分析是Java虚拟机中垃圾收集的核心算法之一,它主要通过判断对象是否能够从一组称为”GC Roots“的根对象出发,通过引用链追踪,最终判断对象是否可达。以下是关于可达性分析的一些详细细节和Java代码示例

  1. GC Roots: GC Roots包括虚拟机栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象以及本地方法栈中JNI(Java Native Interface)引用的对象。这些对象被认为是程序的根对象,是可达性分析的起始点。

  2. 可达性分析过程: 从GC Roots出发,通过对象引用链逐步追踪,判断对象是否能够被程序访问到。如果对象能够通过一系列引用到达GC Roots,则该对象被认为是可达的;反之,如果无法到达,则被认为是不可达的。

  3. 标记-清除算法: 在可达性分析过程中,标记-清除算法是一种常用的垃圾收集算法。通过标记可达的对象,然后清除不可达的对象,最终回收被标记的垃圾。

下面是一个简单的Java代码示例,演示了可达性分析的基本原理:

class MyClass {
    // 成员变量,作为引用
    private MyClass reference;

    public MyClass() {
        this.reference = null;
    }

    public void setReference(MyClass anotherObject) {
        this.reference = anotherObject;
    }
}

public class ReachabilityAnalysisExample {
    public static void main(String[] args) {
        // 创建对象1
        MyClass obj1 = new MyClass();
        // 创建对象2
        MyClass obj2 = new MyClass();

        // obj1 的 reference 成员变量指向 obj2
        obj1.setReference(obj2);

        // obj2 的 reference 成员变量为空,不指向其他对象

        // 现在,obj1 和 obj2 都是可达的,因为它们可以通过引用链相互访问

        // 将 obj1 置为 null,切断对 obj1 的引用
        obj1 = null;

        // 现在,obj1 不可达,因为没有其他引用指向它,但 obj2 仍然可达

        // 执行垃圾回收
        System.gc();

        // 垃圾回收器可能会回收不可达的对象,释放其占用内存

        // 在实际应用中,Java 虚拟机会根据不同的垃圾收集算法和策略执行垃圾回收
    }
}

3、强引用

强引用是最常见的引用类型,只要强引用存在,垃圾收集器就不会回收被引用的对象。当没有任何强引用指向一个对象时,该对象就变得不可达。

  • 特点: 强引用是最常见的引用类型,它会使对象始终保持存活。只要存在强引用指向一个对象,垃圾收集器就不会回收该对象。

  • 使用场景 大多数对象的引用都是强引用,例如通过 new 操作创建的对象就是强引用。当程序员希望确保对象不被垃圾收集器回收时,使用强引用是合适的。

Object obj = new Object(); // 强引用

4、软引用

软引用用于描述一些还有用但非必需的对象。在系统将要发生内存溢出之前,会尝试回收软引用指向的对象。

  • 特点: 软引用用于描述一些还有用但非必需的对象。当系统内存不足时,垃圾收集器会根据软引用的情况来决定是否回收该对象,以释放内存。

  • 使用场景 软引用通常用于实现缓存策略,允许在内存不足时回收部分缓存而不会导致程序崩溃。

SoftReference<Object> softRef = new SoftReference<>(new Object());
Object obj = softRef.get(); // 获取软引用指向的对象

5、弱引用

弱引用也用于描述非必需对象,但它的生命周期比软引用更短。当垃圾收集器运行时,无论内存是否足够,都会回收被弱引用指向的对象。

  • 特点: 弱引用描述的是非必需对象,其生命周期比软引用更短。当垃圾收集器运行时,无论内存是否足够,都会回收被弱引用指向的对象。

  • 使用场景: 弱引用常用于实现对象缓存,但不希望缓存的对象影响垃圾回收。

WeakReference<Object> weakRef = new WeakReference<>(new Object());
Object obj = weakRef.get(); // 获取弱引用指向的对象

6、虚引用

虚引用是最弱的引用类型,几乎没有保持对象存活的作用。主要用于对象被回收前的一些清理操作

  • 特点: 虚引用是最弱的引用类型,几乎没有保持对象存活的作用。主要用于对象被回收前的一些清理操作。虚引用必须和引用队列(ReferenceQueue)一起使用。

  • 使用场景: 虚引用主要用于跟踪对象被垃圾收集的状态执行一些清理操作或者资源释放。

ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), referenceQueue);
// 虚引用不提供 get 方法,因为其并不保持对象的存活,需要通过 ReferenceQueue 来获取通知
Object obj = phantomRef.get(); // 返回始终为 null

 总体而言,这些引用类型在Java中提供了更灵活的内存管理手段,允许开发人员根据不同的场景来控制对象的生命周期。选择合适的引用类型取决于应用程序的需求,以及对内存使用和性能的权衡。

原文地址:https://blog.csdn.net/AliceNo/article/details/134607518

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_2037.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注