【Java 强,弱,软,虚四种引用类型】

在这里插入图片描述

一、强引用

  • 特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。
    当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略

栗子:

  • 下面以HashMap为例,我们看看HashMap键值对中的:key是不是强引用
public class Test {
    
    
    public static void main(String[] args) {
    
    

        //强引用
        String s1 = new String("s1");
        String s2 = new String("s2");

        HashMap<String,Integer> map = new HashMap<>();
        map.put(s1,1);
        map.put(s2,1);
        s1 = s2 = null;
        System.gc();
        System.out.println(map);

    }
}
  • 运行结果:
{
    
    s1=1, s2=1}

分析:我们看到上面代码,我们创建了两个强引用:s1,s2;作为HashMap中的key传入,然后我们把s1,s2值为null,调用System.gc();,但是HashMap还是正常输出了,那么显而易见:HashMap存储的key是强引用

注意:我上述代码其实并不严格,因为调用:System.gc();并不是说垃圾回收立刻就过来回收我们的:s1,s2;通俗说,我们只是给GC一个信息:老哥,待会过来帮我清理下垃圾;至于什么时候来,那是由JVM来调度分配的,大家知道就好了!

二、软引用

  • 特点:当发生GC时候,只有当内存不够用时候,这些软引用的对象才被回收
  • 应用:聊天记录,视频缓存

栗子:

  • 我们下面以SoftReference为例来看软引用
class MyArray{
    
    
    byte[] array = new byte[1024*1024*3];//3M
}
public class SoftReferenceTest {
    
    
    public static void main(String[] args) {
    
    
        //引用队列:存储被GC回收的对象 判断对象是否被回收
        ReferenceQueue<MyArray> queue = new ReferenceQueue<>();
        //强引用:MyArray a = new MyArray();

        //软引用的创建方式
        SoftReference<MyArray> s = new SoftReference<>(new MyArray(),queue);

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

        //这里再开辟3M内存,让我们堆内存全被占用
        byte[]bytes = new byte[1024*1024*3];

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

三、弱引用

  • 特点:强度比软引用更弱一些,当GC时候,不管内存是否够用都会被回收

栗子:

  • 我们以WeakHashMap为例,来验证WeakHashMap中的key为弱引用
public class WeakHashMapTest {
    
    
    public static void main(String[] args) {
    
    
        WeakHashMap<String,Integer> map = new WeakHashMap<>();

        //强引用
        String s1 = new String("s1");
        String s2 = new String("s2");
        String s3 = new String("s3");
        String s4 = new String("s4");

        //插入元素
        map.put(s1,1);
        map.put(s2,1);
        map.put(s3,1);
        map.put(s4,1);


        //遍历
        Iterator<Map.Entry<String,Integer>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()){
    
    
            Map.Entry<String,Integer> next = iterator.next();
            System.out.println("key: "+next.getKey()+"  value: "+next.getValue());
        }
        //验证WeakHashMap中的key是弱引用
        System.out.println("-----------------");
        //释放强引用
        s1 = s2 = s3 = s4 = null;
        System.gc();

        System.out.println(map);
    
    }
}

运行结果:

key: s4  value: 1
key: s3  value: 1
key: s1  value: 1
key: s2  value: 1
-----------------
{
    
    }
  • 分析:同开始的HashMap一样,我们也是创建了几个强引用作为WeakHashMap的key值,当我们把强引用值为null,然后调用GC,我们看到输出结果为:{};也就是被回收了

四、虚引用

  • 特点:不会对对象造成任何影响。和引用队列联合是用来判断这个对象是否被回收

栗子

  • 我们以PhanReference为栗看看虚引用
class Mrray{
    
    
    byte[]bytes = new byte[1024*1024*3];
}
public class PhanReferenceTest {
    
    
    public static void main(String[] args) {
    
    
        //引用队列:存储被GC回收的对象 判断对象是否被回收
        ReferenceQueue<Mrray> queue = new ReferenceQueue<>();

        //虚引用
        PhantomReference<Mrray> ptr = new PhantomReference<>(new Mrray(),queue);

        System.gc();
        try {
    
    
            Thread.sleep(1000);//让GC充分发生  等待一会儿
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println(queue.poll());//队列能够获取到这个对象说明这个对象被回收了
    }
}
  • 虚引用是使用PhantomReference创建的引用,虚引用也称为幽灵引用或者幻影引用,是所有引用类型中最弱的一个。一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用获得一个对象实例

猜你喜欢

转载自blog.csdn.net/qq_44682003/article/details/110669273