java中的几种引用的理解

Java中的四种引用

  • FinalReference 强引用
  • SoftReference 软引用
  • WeakReference 弱引用
  • PhantomReference 虚引用

为什么提供这四种引用

  • 1、方便jvm进行垃圾回收
  • 2、方便开发人员使用,开发人员可以灵活的决定某些对象的生命周期

四种引用的使用

FinalReference 强引用

类似于Object o = new Object()这类的引用,创建一个对象后,该引用会被保存在jvm中,而且只要强引用存在,垃圾回收器就不会回收调被引用的对象

日常使用

强引用的例子比比皆是,我们日常开发中我们经常会去new一个对象,而该new出来的对象便是强引用,也就是说只要该引用存在,垃圾回收器就不会被回收掉

JVM怎么知道引用是否存不存在(见另一篇文章介绍) JVM判断对象是否存活

SoftReference软引用

软引用关联的对象,在内存不够的情况下,会把这些软引用关联的对象列入垃圾回收范围中,然后进行垃圾回收,也就是说软引用并非完全安全的,在内存不够的情况下是会被垃圾回收器回收掉的. demo代码:

public class SoftReferenceDemo {
    public static void main(String[] args) {
        int count = 5;
        SoftReference[] softReferences = new SoftReference[count];
        for (int i = 0; i < count; i++) {
            softReferences[i] = new SoftReference<TestObject>(new TestObject("TestObject-" + i));
        }
        //3、打印出softReference中所有的对象
        for (int i = 0; i < count; i++) {
            Object o = softReferences[i].get();
            if (o == null) {
                System.out.println("null");
            } else {
                System.out.println(((TestObject)o).name);
            }
        }
    }
}
复制代码

这里实例了多个大对象,然后放入softReferences数组中,之后便遍历打印出其中的对象的命名,打印结果如下:

null
null
null
null
TestObject-4
复制代码

通过结果可以看出,前面四个对象因为内存不够而被垃圾回收器回收了

日常使用:

软引用是用来表示某个引用会被GC(垃圾处理器)收集的类。 当有引用指向某个obj的时候,通常发生GC的时候不会把这个对象处理掉,但是被软引用包装的对象,当应用内存将要被耗尽的时候-->即将发生OOM,垃圾处理器就会把它带走。这么看来,软应用的生命周期还是很长的,可以用来做缓存处理。

可以用以下方式创建一个引用:

SoftReference<String> ref = new SoftReference<String>("Hello world");

接收数据:

String value = ref.get();

if (value == null) {
  // 如果被GC回收了 在这里重新初始化
}
// 逻辑处理
...
复制代码

软引用用作缓存:

public class SoftReferenceCache<K,V> {
    private final HashMap<K, SoftReference<V>> mCache;

    public SoftReferenceCache() {
        mCache = new HashMap<K, SoftReference<V>>();
    }

    /**
     * 将对象放进缓存中,这个对象可以在GC发生时被回收
     *
     * @param key key的值.
     * @param value value的值型.
     */

    public void put(K key, V value) {
        mCache.put(key, new SoftReference<V>(value));
    }

    /**
     * 从缓存中获取value
     *
     * @param key
     *
     * @return 如果找到的话返回value,如果被回收或者压根儿没有就返* 回null
     */

    public V get(K key) {
        V value = null;

        SoftReference<V> reference = mCache.get(key);

        if (reference != null) {
            value = reference.get();
        }

        return value;
    }

    /**
     * 从缓存中根据k删除对象
     * @param key
     */
    public void delete(K key){
        mCache.remove(key);
    }
}
复制代码

WeakReference使用

弱引用比软引用更弱,被弱引用关联的对象只能存活到发生下一次垃圾回收之前,也就是说当发生GC时,无论当前内存是否足够,都会被回收掉

demo代码:

public class WeakReferenceDemo {
    public static void main(String[] args) {
        WeakReference<String> sr = new WeakReference<>(new String("i am here"));
        System.out.println(sr.get());
        //手动gc
        System.gc();
        System.out.println(sr.get());
    }
}
复制代码

先构建一个弱引用对象,然后在GC前先打印出来证明它存在过,之后手动调用gc,再次打印,可以看到对象已经没了.运行结果如下:

i am here
null
复制代码

PhantomReference虚引用

虚引用和上面不同的地方在于,一个对象是否有虚引用的存在,完全不会对其生存时间构成如何影响,并且也无法通过虚引用来获取一个对象的实例,也就是说跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收.

虚引用的作用就是能在这个对象被收集器回收时收到一个系统通知,实现追踪垃圾收集器的回收动作,比如在对象被回收的时候,会调用该对象的finalize方法.

  • ReferenceQueue 引用队列

ReferenceQueue引用其实也可以归纳为引用中的一员,可以和上述三种引用类型组合使用[软引用、弱引用、虚引用]

在创建Reference时,手动将Queue注册到Reference中,而当该Reference所引用的对象被垃圾收集器回收时,JVM将会将该Reference放到队列中,而我们便可以对该队列做些其他业务,相当于一种通知机制

demo代码:

public class PhantomReferenceDemo {
    public static void main(String[] args) {
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> phantomReference = new PhantomReference<>(new String("i am here"), referenceQueue);

        //一直返回null,PhantomReference的get()结果必定为null
        System.out.println("phantomReference.get()=" + phantomReference.get());

        System.gc();

        Reference<?> reference;

        while ((reference = referenceQueue.poll()) != null) {
            if (reference == phantomReference) {
                System.out.println("被回收来");
            }
        }
    }
}
复制代码

运行结果:

phantomReference.get()=null
被回收了
复制代码

从结果中可以看到从引用中get出来的对象为null,说明无法通过虚引用来获取一个对象的实例,并且在回收后会被放入队列中

Reference相关的概念

为了方便JVM进行管理,Reference是有状态的,可以分为以下四种状态:

  • active一般来说内存一开始被分配的状态,而当引用的对象的可达性发生变化后gc就会将引用放入pending队列并将其状态改为pending状态
  • pending指的是准备要被放进pending队列的对象
  • enqueue指的是对象的内存已经被回收来
  • inactive这是最终的状态,不能再变为其他状态

转载于:https://juejin.im/post/5d08b9f9e51d4577770e738c

猜你喜欢

转载自blog.csdn.net/weixin_33885676/article/details/93166281