Java中的四种引用(强引用、软引用、弱引用、虚引用)

前言

一般来讲,在你写的代码中的所有对象都是强引用,其他的三个引用都需要你通过Java的类实现.以下是在Java中使用这四种引用的示例:

        //强引用
        Object object = new Object();
        //软引用
        SoftReference<String> softReference = new SoftReference<>("soft");
        //弱引用
        WeakReference<String> weakReference = new WeakReference<>("weak");
        //虚引用,虚引用必须使用引用队列
        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
        PhantomReference<String> phantomReference = new PhantomReference<>("phantom",referenceQueue);

强引用

对于JVM中的GC机制来说,只要存在强引用该对象就不会被清除,即使这会导致OOM(堆内存溢出)的异常.

值得注意的是,由于强引用不会被清楚对象的特性,所以在一段代码中,如果一个对象只是在代码的初始块有需求,而在后部分代码就不需要时,可以考虑通过将该引用置为null来显式的让GC去回收该对象.

    public static void test(List<String> list){
        List<String> gets = new LinkedList<>();

        for (String s : list) {
            if (s.startsWith("get")){
                gets.add(s);
            }
        }
        List<String> targets = new LinkedList<>();
        for (String get : gets) {
            if (get.endsWith("me")){
                targets.add(get);
            }
        }
        //以下的代码就不需要使用gets这个列表了,但是由于强引用的特点,这段空间一直没有释放
        //此时可以考虑手动把引用置空,好释放不必要的空间
        gets = null;
        //值得注意的是,List中有一个clear方法,能够将所有的引用置为null
        //比方说LinkedList,链表,它会将所有的next指针、pre指针以及自身都置为空
        gets.clear();
        //对targets列表的处理
        //...省略不写
        //...
    }

对于手动置空,你需要考虑实际情况,当时间相差不大,也就是程序的执行时间达不到GC的安全点,则不需要自己去手动置空.

但即使置为空,也不一定会被清除,这是因为GC机制来说,对于不可达的对象,只是会处于一个缓刑阶段.

要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。

被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。

软引用

软引用的特点是,当空间足够的时,它不会被GC所回收,只有当堆的空间不足时,才会去清除所有的软引用对象.

软引用的常见场景就是浏览器的返回按钮,当点击返回按钮时,如果内存中该页面的数据没有被清楚,则会被立即反映在页面上.

弱引用

简单来说,就是将对象留在内存的能力不是那么强的引用。当垃圾回收器扫描到只具有弱引用的对象,不管当前内存空间是否足够,都会回收内存。

public class Main {
    public static void main(String[] args) {

        A a = new A();
        B b = new B(a);
        a = null;
        System.gc();
        System.out.println(b.getA());  // null

    }

}

class A {}

class B {

    WeakReference<A> weakReference;

    public B(A a) {
        weakReference = new WeakReference<>(a);
    }

    public A getA() {
        return weakReference.get();
    }
}

虚引用

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

虚引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

引用队列

所有的引用中,强引用和引用队列没有关系,软引用和弱引用都是可以用引用队列,而虚引用是必须使用引用队列.这一点体现在他们的构造方法上.

    public SoftReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
        this.timestamp = clock;
    }
    
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

JVM 负责设置可回收的对象引用 Reference 的内部状态及断开与被引用对象的关系,而 Reference 内部线程会不断轮询处理可回收的引用 Reference,把可回收的引用存放到引用队列,接着 JVM 垃圾回收机制按照队列中的顺序回收元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值