Java中的四种引用

    static class Person {
        String mName;
        public Person(String name) {
            mName = name;
        }
        @Override
        public String toString() {
            return "person[" + mName + "]";
        }
    }

1.强软弱虚四种引用

1.1 强引用

    public static void strongRef() {
        try {
            Person person = new Person("张三");
            Person strong = person;
            person = null;
            System.gc();
            Thread.sleep(1000);
            System.out.println(strong);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行结果:

person[张三]

解释:
强引用是JVM的默认实现,即使内存不足会导致OOM(OutOfMemory)时,强引用关联的对象也不会被回收。

1.2 软引用

       public static void softRef() {
            try {
                Person person = new Person("李四");
                ReferenceQueue rq = new ReferenceQueue();
                SoftReference sr = new SoftReference(person, rq);
                person = null;
                System.gc();
                Thread.sleep(1000);
                System.out.println("sr.get():" + sr.get());
                System.out.println("rq.poll():" + rq.poll());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

内存足够的情况下的执行结果:

sr.get():person[李四]
rq.poll():null

内存不足的情况下的执行结果:

sr.get():null
rq.poll():java.lang.ref.SoftReference@15db9742

解释:

  1. 某个对象只被软引用关联,当JVM内存不足时,该对象会被回收。也就是说在JVM抛出OutOfMemoryError之前,会去清理只被软引用关联的对象。
  2. 软引用可以与引用队列ReferenceQueue联合使用。当只被软引用关联的对象(即Person对象)被回收后,其相应的包装类对象(即SoftReference对象)会被加入到ReferenceQueue队列中。
  3. 包装类对象被加入到ReferenceQueue队列中后,调用其poll()方法可以获取该队列中的包装类对象。

1.3 弱引用

    public static void weakRef() {
        try {
            Person person = new Person("王五");
            ReferenceQueue rq = new ReferenceQueue();
            WeakReference wr = new WeakReference(person, rq);
            System.out.println("wr.get():" + wr.get());
            person = null;
            Reference reference;
            while (true) {
                System.out.println("-----");
                reference = rq.poll();
                if (wr.equals(reference)) {
                    System.out.println("wr.get():" + wr.get());
                    System.out.println("被回收了");
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行结果:

wr.get():person[王五]
----
----
----
...
wr.get():null
被回收了

解释:
当某个对象只被弱引用关联时,无论内存是否足够,只要 JVM 开始进行垃圾回收,该对象都会被回收。

1.4 虚引用

    public static void phantomRef() {
        Person person = new Person("朱六");
        ReferenceQueue rq = new ReferenceQueue<>();
        PhantomReference pr = new PhantomReference(person, rq);
        System.out.println("pr.get():" + pr.get());
        person = null;
        Reference reference;
        while (true) {
            System.out.println("-----");
            reference = rq.poll();
            if (pr.equals(reference)) {
                System.out.println("被回收了");
                break;
            }
        }
    }   

执行结果:

pr.get():null
-----
-----
-----
...
被回收了

解释:

  1. 虚引用必须与引用队列ReferenceQueue联合使用
  2. 虚引用的get()方法永远返回null
  3. 当JVM发现一个对象只被虚引用关联时,则会将虚引用加入ReferenceQueue队列中,然后当JVM垃圾回收时回收该对象

注意:虚引用是先将包装类PhantomReference对象加入ReferenceQueue队列中,然后Person对象才被JVM回收;而软引用和弱引用则相反,是Person对象先被JVM回收,然后才...

2.四种引用的应用场景:

  1. 强引用,不解释。
  2. 软引用,适用于网页、图片、视频等缓存。
    比如app内有一张图片,这张图片很多地方都会用到,如果每次用到的时候都去读取图片,大量的重复读取会导致性能下降,此时可以将图片缓存起来,需要的时候直接从内存中读取,但是由于图片占的内存空间比较大,缓存的图片过多就有可能发生OOM,这时就可以使用软引用。
  3. 弱引用,适用于可能会发生内存泄漏的地方。比如Android中的Handler,参见博客Android Handler详解
  4. 虚引用,在程序中可以判断PhantomReference是否已经被加入ReferenceQueue队列中,如果是,则说明虚引用关联的对象即将被回收,可以在回收之前执行一些必要的业务逻辑。

你可能感兴趣的:(Java中的四种引用)