Java中四种引用概念分析以及代码使用示例

强引用

强引用一般就是我们经常见到使用的引用关系,通过new一个对象,建立一个强引用关系;如:Person person=new Person()
即使内存不够报OOM,GC也不会回收强引用对象;

软引用

在Java中通过SoftReference建立软引用关系
软引用特点就是:在内存不足的时候会回收该对象,内存足够的时候不会回收

import java.lang.ref.SoftReference;

/**
 * @Author: xiaoshijiu
 * @Date: 2020/2/27
 * @Description: $value$
 */
public class SoftReferenceDemo2 {

    /**
     * 通过-Xmx10m -Xms10m
     * 给虚拟机分配的最大内存空间为10m
     */
    public static void main(String[] args) {

        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 6]);

        // 10m的内存空间足够,第一个对象的创建
        System.out.println(softReference.get());

        SoftReference<byte[]> softReference2 = new SoftReference<>(new byte[1024 * 1024 * 5]);

        // 剩余的内存空间不足够创建第二个对象,所以回收第一个虚引用对象,不报内存溢出
        System.out.println(softReference.get());
        // System.out.println(softReference);
        System.out.println(softReference2.get());

    }
}

运行结果:
在这里插入图片描述
从上面的代码看出 :在创建了第二个软引用对象之后,第一个软引用对象就被GC回收了
注:get()方法可以获取经过软引用包装的对象

软引用还可以用作本地缓存,因为缓存需要加载到内存中,但是内存也有一定的大小限制,无限的加入肯定会出现内存溢出,如果缓存的对象使用了软引用包装,那就可以在内存紧张的时候及时回收;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: xiaoshijiu
 * @Date: 2020/2/27
 * @Description: 因为软引用的特点:内存不足的时候进行回收,所以模拟应用本地缓存
 */
public class SoftReferenceCacheDemo {

    Map<String, SoftReference<byte[]>> map = new HashMap<>();

    /**
     * 放入缓存
     */
    public void setCache(String id, byte[] cache) {
        map.put(id, new SoftReference<>(cache));
    }

    /**
     * 取缓存
     */
    public byte[] getCache(String id) {
        SoftReference<byte[]> reference = map.get(id);
        if (reference != null) {
            // 没取到,即被gc清理了
            byte[] myCache = reference.get();
            return myCache == null ? null : myCache;
        }
        return null;
    }
}

这里使用 byte[] 是为了方便测试

测试代码:

 // 一样,通过-Xmx10m -Xms10m给虚拟机分配的最大内存空间为10m
 public static void main(String[] args) {

        SoftReferenceCacheDemo softReferenceCacheDemo = new SoftReferenceCacheDemo();

        softReferenceCacheDemo.setCache("aaa", new byte[1024 * 1024 * 5]);

        System.out.println(softReferenceCacheDemo.getCache("aaa"));

        // 10m内存,不足以创建这个对象,所以回收上面那个缓存对象
        softReferenceCacheDemo.setCache("bbb", new byte[1024 * 1024 * 6]);

        System.out.println(softReferenceCacheDemo.getCache("aaa"));
        System.out.println(softReferenceCacheDemo.getCache("bbb"));
    }

运行结果:
在这里插入图片描述
可见:我们的缓存建立成功,会大大减少 OOM 的可能性

弱引用

弱引用比软引用的引用关系还要弱一点,只要GC工作,就会回收弱引用对象;
使用WeakReference包装,API和软引用SoftReference类似;

import java.lang.ref.WeakReference;

/**
 * @Author: xiaoshijiu
 * @Date: 2020/2/27
 * @Description: 弱引用:只要gc工作就一定会回收该对象,不论内存充不充足
 */
public class WeakReferenceDemo {

    public static void main(String[] args) {

        WeakReference<Object> weakReference = new WeakReference<>(new Object());

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

        System.gc();

        // 引用回收的只是 被引用对象,而不是 本身对象

        System.out.println(weakReference.get());
        System.out.println(weakReference); // 仍然存在
    }

}

运行结果:
在这里插入图片描述
经过GC之后,弱引用对象被回收了;

注意:SoftReferenceWeakReference一样,被GC回收的只是经过他们包装的对象,并不是他们本身对象被回收了;通俗讲就是:get()方法获得的对象为null,但是自己本身不是;

虚引用

虚引用顾名思义就是虚幻的引用,即不存在的引用关系;
使用PhantomReference包装,他的API跟前面两种引用有不同
第一:他的get()方法写死了,定返回null(也就是跟前面不一样,不能通过get()方法获取被包装的对象)
在这里插入图片描述
第二:他的构造方法只有一个,必须是一个 “被包装的对象" + 一个 引用队列;即他的使用必须搭配引用队列
在这里插入图片描述
当进行GC之前,会将虚引用放到该引用队列中,用来跟踪对象被GC回收的活动;
这样一来,就可以在被回收之前采取一些行动;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
 * @Author: xiaoshijiu
 * @Date: 2020/2/27
 * @Description: 虚引用:又叫幻引用,其实是一种不存在的引用,需要与引用队列一起使用;
 *               GC工作时,将虚引用添加至引用队列;虚引用,可以在要被回收的时候做一些指定的事
 */
public class PhantomReferenceDemo {

    public static void main(String[] args) throws InterruptedException {

        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();

        // 虚引用必须要和引用队列一起使用,他的get方法永远返回null
        PhantomReference<byte[]> phantomReference = new PhantomReference<>(new byte[1024*1024*5], queue);


        System.out.println(queue.poll());

        System.gc();

        Thread.sleep(300L);

        System.out.println(queue.poll());   
    }
}

运行结果:
在这里插入图片描述
主动进行GC,将虚引用添加至了关联的队列中;

有关虚引用所指向的对象被回收的时机问题,另一篇博客有详细分析

虚引用所指向的对象到底什么时候被回收?

可以看看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值