自学内容网 自学内容网

强引用、软引用、弱引用、虚引用用法

强引用、软引用、弱引用、虚引用用法

强引用

强引用是指程序中在程序代码之中类似“Object obj = new Object()”的引用关系,无论任何情况下,只要强引用关系还存在,垃圾回收器就不会回收掉被引用的对象。
强引用是我们最常用的引用,没什么好讲的,在集合源码中也可以见到将强引用置为null来使对象被回收的操作:

    /**
     * HashMap中的清除方法,将所有节点遍历置为null
     * 使不可达对象在下次gc时被回收
     */
    public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }

弱引用

在虚拟机抛出OutOfMemoryError之前,所有对软可达对象的软引用都保证已被清除。也就是说在发生内存溢出之前会先清除软引用,并且软引用对象也会被清除。
这样我们就可以利用软引用做一层缓存,在空间充足的时候保存一些文件,在空间紧张时自动清理并且做一些善后操作。


public class test {
    public static void main(String[] args) {
        softReferenceOverHeadLimitResolve();
    }
    private static void softReferenceOverHeadLimitResolve() {
        int capacity = 1024 * 1024;
        //用来保存对象
        HashSet<SoftReference<SmallSoftObject>> set = new HashSet<>(capacity);
        // 引用队列,被清除的软引用会进入这个队列中,这个队列我们之后还会再用到
        ReferenceQueue<SmallSoftObject> referenceQueue = new ReferenceQueue<>();
        for (int i = 0; i < capacity; i++) {
        // 保存文件
            set.add(new SoftReference<>(new SmallSoftObject(), referenceQueue));
            // 如果之前保存的文件因为空间不足被清理,可以在这个方法里执行善后处理
            removeObject(set, referenceQueue);
        }
        System.out.println("End");
    }

    private static void removeObject(HashSet<SoftReference<SmallSoftObject>> set, ReferenceQueue<SmallSoftObject> referenceQueue) {
    //获得被清理的软引用,在set中删除
        Reference<? extends SmallSoftObject> poll = referenceQueue.poll();
        while (poll != null) {
            set.remove(poll);
            poll = referenceQueue.poll();
        }
    }

    static class SmallSoftObject {
        byte[] data = new byte[1024];
    }
}

现在我们添加运行参数,修改堆大小模拟内存不够的情况,并开启gc日志

-Xmx40m -XX:+PrintGC

在这里插入图片描述
以下是运行结果
在这里插入图片描述

弱引用

弱引用在下次垃圾回收发生时就会被回收。

WeakReference<byte[]> wk = new WeakReference<byte[]>(new byte[1024 * 1024 * 100]);
        System.out.println(wk.get());
        System.gc();
        System.out.println(wk.get());

在这里插入图片描述

虚引用

虚引用被回收后会进入引用队列等待,查看代码发现只有一个带队列的构造方法:
在这里插入图片描述
那么我们使用虚引用的目的就是当对象被回收,虚引用会进入引用队列,这是我们从引用队列取出引用后得知对象被回收的信息,进行验尸工作。

public class test {
    public static void main(String[] args) {
        testPhantomReference();
    }


    public static void testPhantomReference() {
        ReferenceQueue rq = new ReferenceQueue();
        byte[] bytes = new byte[1024 * 1024 * 100];

        PhantomReference<byte[]> pr = new PhantomReference<byte[]>(bytes, rq);

        //监控对象是否被清理
        Thread cleanUpThread = new Thread(() -> {
            try {
                while(true){
                    Reference remove = rq.remove();
                    System.out.println("对象被清理了" + remove);
                }
                } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        );
        cleanUpThread.setDaemon(
                true
        );
        cleanUpThread.start();

        bytes = null;
        System.gc();
    }

这里我们启动一个守护线程去监控对象是否被清理,如果被清理则打印清理内容
在这里插入图片描述


原文地址:https://blog.csdn.net/yuanyajieh/article/details/142742283

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!