Java 中的四种引用使用场景分析

版权声明:码字不易,欢迎点赞。 https://blog.csdn.net/weixin_40255793/article/details/82793656

强引用

强引用的对象,永远不会被垃圾回收,JVM 宁愿抛出 OutOfMemeory 错误也不会回收这种对象。

软引用 soft

没有强引用而只有软引用的对象,只要内存空间足够,垃圾回收器就不会回收(严谨的说法是,GC 根据内存使用情况酌情考虑什么时候回收)。

MyObject aStrongRef = new MyObject();
SoftReference aSoftRef = new SoftReference(aStrongRef);
aStongRef = null; // 此时这个对象只有软引用,没有强引用
aStrongRef = aSoftRef.get(); // 返回 null,或者新的强引用

当软引用在 OutOfMemory 之前被回收后,软引用变量不再有存在的价值,但是他们本身还是强引用,太多的软引用变量同样会导致 OutOfMemory 问题。其实,我们可以在创建软引用变量时,指定一个 ReferenceQueue,当软引用变量不再有存在的价值时,会被插入到队列中,我们可以利用此队列回收这些软引用变量。

Set<SoftReference<MyObject>> cache = new HashSet<>();
cache.add(new SoftReference(aStrongRef, queue));
//...
Reference<? extends MyObject> ref = queue.poll();
while (ref != null) {
    if (cache.remove(ref)) {
        removedSoftRefs++;
    }
    ref = queue.poll();
}

软引用可以被用于缓存对象,尤其那些重新实例化的开销很大的对象。

弱引用 weak

用来描述非必需对象,当 JVM 进行垃圾回收时,无论内存是否充足,都会回收没有强、软引用而只有弱引用的对象。

WeakHashMap 的特色是使用了弱引用的键,它可以被当做标准 Map 使用,不一样的地方是,当键被 GC 回收时,它会自动清理该键值对。

public class ExampleWeakHashMap {
    public static Map<Integer,String> cache = new WeakHashMap<Integer, String>();
 
    public static void main(String[] args) {
        Integer i5 = new Integer(5);
        cache.put(i5, "five");
        i5 = null;
        // the entry {5,"five"} will stay in the Map until the next garbage collector call
 
        Integer i2 = 2;
        // the entry {2,"two"} will stay  in the Map until i2 is no more strongly referenced
        cache.put(i2, "two");
 
        // the OutOfMemoryError won't happen, because the Map will clear its entries.
        for (int i = 6; i < 100_000_000; i++) {
            cache.put(i,String.valueOf(i));
        }
    }
}

在规范化映射中,可以使用 WeakHashMap<String,Map<K,V>> 保存多个事务的信息,String 类型的键保存事务的 ID,简单的 Map 中保存了事务生命周期中需要的信息,在事务的生命周期中,String 对象的强引用一直存在,所以我们可以一直获取它的信息,当事务结束后,弱引用可以自动帮助我们清理 Map 信息。

虚引用 phantom

在垃圾回收进程中,没有强、软引用的对象会被删除,在被删除前,会先调用对象的 finalize() 方法。当一个对象被 finalized 但是还没有被删除完,它就处于“虚可达”的状态,这意味着只有一个 GC 根节点和该对象之间的一个虚引用。

ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> aPhantomRef = new PhantomReference<String>(new String("string"), queue);

和软、弱引用不一样,对一个对象的显式的虚引用会阻止该对象被删除。程序员需要显式或者隐式地移除此虚引用,才能使得 finalized 对象被销毁。显式地销毁虚引用要用到 ReferenceQueue,当虚可达的对象被 finalized 后,队列中会入队此对象。但是虚引用不能获得此对象,get() 方法总是返回 null,程序员不能使虚可达的对象再次强、软、弱可达。这也很好理解,因为在重写的 finalize() 方法中通常要清理各种资源,使得对象不能继续工作。

虚引用的使用场景,可能是,当你需要在对象被 finalized 之后做一些处理,但是又不能重写 finalize() 方法时(处于性能和可靠性的考虑,Effective Java 3 rd 中不建议使用 finalizer 和 cleaner)。

参考资料

  1. References in JAVA

猜你喜欢

转载自blog.csdn.net/weixin_40255793/article/details/82793656
今日推荐