你真的理解JAVA四种引用类型吗?

在JVM中,垃圾回收器作为管理jvm内存空间的模块,需要对是否回收某个对象的内存空间进行判断,因此java中定义了引用类型作为垃圾回收机制的判断标准。

JAVA中的四种引用类型:强引用 软引用  弱引用  虚引用

Reference类

强引用:把一个对象赋给一个引用变量,这个引用变量就是一个强引用,表明对象是可达的。被强引用的对象不能被垃圾回收机制回收,是造成内存泄漏的主要原因之一。一般我们使用的都是强引用。

 

 

其余三种引用一般都与引用队列共同使用

软引用:软引用需要用SoftReference实现,内存空间不足时回收,内存足够时候不回收(类似于家里闲置的物品)

 /**
     * 软引用
     * 只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收
     *
     * <pre>
     * 无论是否发送GC,执行结果都是:
     * java.lang.Object@f9f9d8
     * null
     * java.lang.Object@f9f9d8
     * null
     * </pre>
     *
     * 可以看到:只有发送了GC,将对于从内存中释放的时候,JVM才会将reference加入引用队列
     */
    @Test
    public void soft()throws Exception
    {
        Object obj = new Object();
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
        SoftReference<Object> softRef = new SoftReference<Object>(obj, refQueue);
        System.out.println(softRef.get()); // java.lang.Object@f9f9d8
        System.out.println(refQueue.poll());// null

        // 清除强引用,触发GC
        obj = null;
        System.gc();

        System.out.println(softRef.get());

        Thread.sleep(200);
        System.out.println(refQueue.poll());
    }

 

弱引用:WeakReference实现,类似软引用,但总会被回收

 /**
     * 弱引用(WeakReference): 当发生GC的时候,Weak引用对象总是会内回收回收。因此Weak引用对象会更容易、更快被GC回收。
     * Weak引用对象常常用于Map数据结构中,引用占用内存空间较大的对象
     *
     * <pre>
     * 如果不发生垃圾回收:
     * java.lang.Object@f9f9d8
     * null
     * java.lang.Object@f9f9d8
     * null
     *
     * 如果发生垃圾回收:
     * java.lang.Object@f9f9d8
     * null
     * null
     * java.lang.ref.WeakReference@422ede
     *
     * <pre>
     */
    @Test
    public  void weak() throws Exception
    {
        Object obj = new Object();
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
        WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);
        System.out.println(weakRef.get()); // java.lang.Object@f9f9d8
        System.out.println(refQueue.poll());// null

        // 清除强引用,触发GC
        obj = null;
        System.gc();

        System.out.println(weakRef.get());

        // 这里特别注意:poll是非阻塞的,remove是阻塞的.
        // JVM将弱引用放入引用队列需要一定的时间,所以这里先睡眠一会儿
        // System.out.println(refQueue.poll());// 这里有可能是null

        Thread.sleep(200);
        System.out.println(refQueue.poll());
        // System.out.println(refQueue.poll());//这里一定是null,因为已经从队列中移除

        // System.out.println(refQueue.remove());
    }

 

虚引用:PhantomReference, ,它不能单独使用,必须和引用队列联合使用。虚 引用的主要作用是跟踪对象被垃圾回收的状态。

 /**
     * 当GC一但发现了虚引用对象,将会将PhantomReference对象插入ReferenceQueue队列.
     * 而此时PhantomReference所指向的对象并没有被GC回收,而是要等到ReferenceQueue被你真正的处理后才会被回收.
     *
     * <pre>
     * 不发生GC执行结果是:
     * null
     * null
     * null
     * null
     *
     * 发生GC执行结果是:
     * null
     * null
     * null
     * java.lang.ref.PhantomReference@87816d
     * </pre>
     *
     * 虚引用在实现一个对象被回收之前必须做清理操作是很有用的,比finalize()方法更灵活
     */
    @Test
    public void phantom() throws Exception
    {
        Object obj = new Object();
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
        PhantomReference<Object> phantom = new PhantomReference<Object>(obj,refQueue);
        System.out.println(phantom.get()); // java.lang.Object@f9f9d8
        System.out.println(refQueue.poll());// null

        obj = null;
        System.gc();

        // 调用phanRef.get()不管在什么情况下会一直返回null
        System.out.println(phantom.get());

        // 当GC发现了虚引用,GC会将phanRef插入进我们之前创建时传入的refQueue队列
        // 注意,此时phanRef所引用的obj对象,并没有被GC回收,在我们显式地调用refQueue.poll返回phanRef之后
        // 当GC第二次发现虚引用,而此时JVM将phanRef插入到refQueue会插入失败,此时GC才会对obj进行回收
        Thread.sleep(200);
        System.out.println(refQueue.poll());
    }

 

 

猜你喜欢

转载自blog.csdn.net/qq_40513633/article/details/107111078
今日推荐