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

引用:变量指向内初中某一块区域(某一个对象)。

强引用

常见的普通引用即是强引用,如:
	Object o = new Object();
强引用的特点是,只要有引用指向该对象,该对象就不会被回收,哪怕发生OOM。看下面案例:
public class TestQuote {
    
    

   /**
    * 对象被回收时会调用该方法,实际工作中不建议覆写该方法
    */
    @Override
    protected void finalize() throws Throwable {
    
    
        System.out.println("我被回收了");
    }
}

public class NormalReference {
    
    

    public static void main(String[] args) throws IOException {
    
    
        TestQuote quote = new TestQuote();
        
        System.gc();

        System.in.read();
    }
}
执行main方法我们可以看到,手动调用了 System.gc(),但是对象没有被回收,对上面的程序稍作改动,则得到以下结果:
public class NormalReference {
    
    

    public static void main(String[] args) throws IOException {
    
    
        TestQuote quote = new TestQuote();
        quote = null;
        System.gc();

        System.in.read();
    }
}
再次运行main方法,我们看到控制台输出了 "我被回收了",证明finalize方法被调用了。

软引用

java中,软引用需要通过 java.lang.ref.SoftReference 来实现,其特点是:当一个对象被软引用指向时,只有系统内存不够用时才会进行回收。常见引用场景:缓存。看如下案例:
public class TestSoftReference {
    
    
    public static void main(String[] args) {
    
    
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
        System.out.println(softReference.get());
        System.out.println("--------------");
        System.gc();
        try {
    
    
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println(softReference.get());
        System.out.println("--------------");
        byte[] bytes = new byte[1024 * 1024 * 12];
        System.out.println(softReference.get());
    }
}
执行main方法,控制台得到如下输出:
[B@74a14482
--------------
[B@74a14482
--------------
null
当然要想得到实现效果需要使用响应的JVM参数来控制程序可以使用的堆内初大小 -Xms20M -Xmx20M,通过以上命令,我们将程序可以使用的堆内存控制在20M。

下面我们分析下程序输出结果,首先我们使用了SoftReference申明了一个10M大小的软引用,通过get方法可以正常拿到该对象(控制台输出的第一行hashCode),然后我们调用了垃圾回收,然后再次调用get方法,仍然可以正常拿到该字节数组。在此申请一个12M大小的字节数组,然后调用get方法,我们发现这时的返回值是null,如此也就证明了上面的观点。

解释:由于内存总大小为20M,第一次使用软引用申请了10M大小的空间,在内存足够的时候该对象不会被回收,再次申请一个12M大小的空间,20-10只有10M空间了,因此软引用对象被回收,再次获取我们得到了null。

弱引用

弱引用需要通过 java.lang.ref.WeakReference 来实现,其特点是:当一个对象被弱引用指向时,只要发生垃圾回收,该对象就会被回收。适用场景:一般用在容器,如 java.util.WeakHashMap,java.lang.ThreadLocal。案例如下:
public class TestWeakReference {
    
    
    public static void main(String[] args) {
    
    
        WeakReference<TestQuote> weakReference = new WeakReference<>(new TestQuote());
        System.out.println(weakReference.get());
        System.out.println("----------");
        System.gc();
        System.out.println(weakReference.get());
    }
}

虚引用

虚引用需要通过 java.lang.ref.PhantomReference 来实现,主要用来管理对外内存,需要配合一个队列来使用,只要触发垃圾回收就一定会被回收,实际工作中实用较少。案例如下:
public class TestPhantomReference {
    
    

    private static final List LIST = new LinkedList();

    private static final ReferenceQueue QUEUE = new ReferenceQueue();

    public static void main(String[] args) {
    
    
        PhantomReference<TestQuote> phantomReference = new PhantomReference<>(new TestQuote(), QUEUE);
        new Thread(() -> {
    
    
            LIST.add(new byte[1024 * 1024]);
            try {
    
    
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
            System.out.println(phantomReference.get());
        }).start();


        new Thread(() -> {
    
    
            while (true) {
    
    
                Reference poll = QUEUE.poll();
                if (poll != null) {
    
    
                    System.out.println("虚引用对象被回收...回收对外内存");
                }
            }
        }).start();


        try {
    
    
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/hxj413977035/article/details/113342137