美文网首页
Java中的四种引用类型

Java中的四种引用类型

作者: Harri2012 | 来源:发表于2019-08-14 11:54 被阅读0次

    引用类型

    引用包括强引用(Strong ref)、软引用(Soft ref)、弱引用(weak ref)、虚引用(幻象引用,PhantomReference)。不同的引用类型, 主要体现的是对象不同的可达性(reachable) 状态
    和对垃圾收集的影响。

    • 强引用 最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。
    • 软引用 相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当JVM认为内存不足时,才会去试图回收软引用指向的对象。JVM会确保在抛出OutOfMemoryError之前,清理软引用指向的对象。软引用通常用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。
    • 弱引用 不能使对象豁免垃圾收集, 仅仅是提供一种访问在弱引用状态下对象的途径。维护一种非强制性的映射关系,如果试图获取时对象还在,就使用它,否则重现实例化。它同样是很多缓存实现的选择。
    • 虚引用 不能通过它访问对象。幻象引用仅仅是提供了一种确保对象被finalize以后,做某些事情的机制,比如,通常用来做所谓的Post-Mortem清理机制,我在专栏上一讲中介绍的Java平台自身Cleaner机制等。

    除了幻象引用(因为get永远返回null),如果对象还没有被销毁,都可以通过get方法获取原有对象。这意味着,利用软引用和弱引用,我们可以将访问到的对象,重新指向强引用,也就是人为的改变了对象的可达性状态!在对象执行finallize方法时也可以使用强引用来挽留对象。

    引用队列(ReferenceQueue)

    当gc(垃圾回收线程)准备回收一个对象时,如果发现它还仅有软引用(或弱引用,或虚引用)指向它,就会在回收该对象之前,把这个软引用对象(或弱引用,或虚引用,注意不是Reference对象的referent。)加入到与之关联的引用队列(ReferenceQueue)中。如果一个软引用(或弱引用,或虚引用)对象本身在引用队列中,就说明该引用对象所指向的对象被回收了。可以通过扩展软引用(或弱引用,或虚引用)来实现在Referent对象入队时,同时做一些清理相关对象的操作。

    软引用、弱引用、虚引用对象本身是个强引用,不会自动被gc回收,需要手动进行调用poll或remove从队列里取出,当不再被引用时自动回收。WeakHahsMap 的实现原理简单来说就是HashMap里面的条目 Entry继承了 WeakReference,那么当 Entry 的 key 不再被使用(即,引用对象不可达)且被 GC 后,那么该 Entry 就会进入到 ReferenceQueue 中。当我们调用WeakHashMap 的get和put方法会有一个副作用,即清除无效key对应的Entry(WeakHashMap的Entry扩展了WeakReference类,同时保存了key的hashcode)。

    TODO 使用引用队列检测内存泄露

    Reachability Fence

    按照Java语言规范,如果一个对象没有指向强引用,就符合垃圾收集的标准,有些时候,对象本身并没有强引用, 但是也许它的部分属性还在被使用,这样就导致诡异的问题,所以我们需要一个方法,在没有强引用情况下,通知JVM对象是在被使用的。

    class Resource {
        private static ExternalResource[] externalResourceArray = ...
        int myIndex; 
        
        Resource(...) {
            myIndex = ...
            externalResourceArray[myIndex] = ...;
            ...
        }
        
        protected void finalize() {
            externalResourceArray[myIndex] = null;
            ...
        }
        
        public void action() {
            try {
                // 需要被保护的代码
                int i = myIndex;
                Resource.update(externalResourceArray[i]);
            } finally {
                // 调用reachbilityFence, 明确保障对象strongly reachable
                Reference.reachabilityFence(this);
            }
        } 
    }
    
    

    方法action的执行,依赖于对象的部分属性,所以被特定保护了起来。否则,如果我们在代码中调用new Resource().action(), 那么就可能会出现困扰,因为没有强引用指向我们创建出来的Resource对象,JVM对它进行finalize操作是完全合法的。类似的书写结构,在异步编程中似乎是很普遍的,因为异步编程中往往不会用传统的“执行->返回->使用”的结构。

    相关文章

      网友评论

          本文标题:Java中的四种引用类型

          本文链接:https://www.haomeiwen.com/subject/bjhgjctx.html