zoukankan      html  css  js  c++  java
  • java中几种reference区别

    Java.lang.ref 是 Java 类库中比较特殊的一个包,它提供了与 Java 垃圾回收器密切相关的引用类。这些引用类对象可以指向其它对象,但它们不同于一般的引用,因为它们的存在并不防碍 Java 垃圾回收器对它们所指向的对象进行回收。其好处就在于使者可以保持对使用对象的引用,同时 JVM 依然可以在内存不够用的时候对使用对象进行回收。因此这个包在用来实现与缓存相关的应用时特别有用。同时该包也提供了在对象的“可达”性发生改变时,进行提醒的机制。

    Java 中有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference。

    1. Strong Reference(强引用)        

        定义:StrongReference 是 Java 的默认引用实现,是使用最普遍的引用。在java.lang.ref里也没有实际的对应类型。 JVM 中对象是被分配在堆(heap)上的,当程序行动中不再有引用指向这个对象时,这个对象就可以被垃圾回收器所回收。这里所说的引用也就是我们一般意义上申明的对象类型的变量(如 String, Object, ArrayList 等),区别于原始数据类型的变量(如 int, short, long 等)也称为强引用。

        描述:如果一个对象具有强引用,它会尽可能长时间的存活于JVM 内,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。当没有任何对象指向它时GC 执行后将会被回收。强引用可以直接访问目标对象;强引用所指向的对象在任何时候都不会被系统回收 ;强引用可能导致内存泄漏。

        @Test
        public void strongReference() {    
           Object ref = new Object();     
           Object strongReference = ref;  
           //Object对象,有两个引用路径,来自strongReference和ref的强引用,Object对象是强可及对象。  
           Assert.assertSame(ref, strongReference);    
           ref = null;    
           System.gc();      
           //strongReference 在 GC 后不会被回收    
           Assert.assertNotNull(strongReference);    
        }  

    2、SoftReference软引用

         定义:SoftReference对象,在响应内存需要时,由垃圾回收器决定是否清除此对象。软引用对象最常用于实现内存敏感的缓存。

        描述:如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

    public void softReference() {    
       Object ref = new Object();    
       SoftReference<Object> softRerference = new SoftReference<Object>(ref);    
       // Object对象有softReference的软引用和ref的强引用,Object对象是强可及对象。  
       assertNotNull(softRerference.get());    
       ref = null;   
       //此时Object对象只有一个softReference引用,Object对象此时是软可及对象。  
       System.gc();    
       // softReferences在OutOfMemory之前才会被回收  
       assertNotNull(softRerference.get());    
    }   

    使用 ReferenceQueue后的使用方法:

    public void softReference() {    
       Object ref = new Object();    
       ReferenceQueue q = new ReferenceQueue();  
       SoftReference softReference = new SoftReference(ref, queue);  
       // Object对象有softReference的软引用和ref的强引用,Object对象是强可及对象。  
       assertNotNull(softRerference.get());    
       ref = null;   
       // Object对象只有一个softReference引用,Object对象此时是软可及对象。  
       System.gc();     
       while ((softReference = (SoftReference) q.poll()) != null) {  
          // softReference = null;  
         }  
    }  

    、WeakReference(弱引用)

          定义:弱引用对象,它们并不禁止其指示对象变得可终结,并被终结,然后被回收。弱引用最常用于实现规范化的映射。

       描述:弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

    弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

    public static void main(String[] args) throws InterruptedException {  
        Object obj = new Object();  
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();  
        WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);  
        System.out.println(weakRef.get());  
        System.out.println(refQueue.poll());  
        obj = null;  
        System.gc();  
        System.out.println(weakRef.get());  
        System.out.println(refQueue.poll());  
    }  

    4、WeakHashMap

         参考:http://www.365doit.com/all/news/weakhashmap.html 

    5. PhantomReference(虚引用)

        定义:虚引用对象,在回收器确定其指示对象可另外回收之后,被加入队列。虚引用最常见的用法是以某种可能比使用 Java 终结机制更灵活的方式来指派 pre-mortem 清除动作。

      描述:hantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行 pre-mortem 清除操作。PhantomReference 必须与 ReferenceQueue 类一起使用。需要 ReferenceQueue 是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时,PhantomReference 对象就被放在它的 ReferenceQueue 上。将 PhantomReference 对象放在 ReferenceQueue 上也就是一个通知,表明 PhantomReference 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。

    public static void main(String[] args) throws InterruptedException {  
        Object obj = new Object();  
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();  
        PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue);  
        System.out.println(phanRef.get());  
        System.out.println(refQueue.poll());  
        obj = null;  
        System.gc();  
        System.out.println(phanRef.get());  
        System.out.println(refQueue.poll());  
    }  

     从执行结果得知,我们先前说的没有错,phanRef.get()不管在什么情况下,都会返回null,而当JVM执行GC发现虚引用之后,JVM并没有回收obj,而是将PhantomReference对象插入到对应的虚引用队列refQueue中,当调用refQueue.poll()返回PhantomReference对象时,poll方法会先把PhantomReference的持有队列queue(ReferenceQueue<? super T>)置为NULL,NULL对象继承自ReferenceQueue,将enqueue(Reference paramReference)方法覆盖为return false,而此时obj再次被GC发现时,JVM再将PhantomReference插入到NULL队列中便会插入失败返回false,此时GC便会回收obj。事实上通过这段代码我们也的却看不出来obj是否被回收,但通过 PhantomReference 的javadoc注释中有一句是这样写的:

    Once the garbage collector decides that an object obj is phantom-reachable, it is being enqueued on the corresponding queue, but its referent is not cleared. That is, the reference queue of the phantom reference must explicitly be processed by some application code.

    翻译一下(这句话很简单,我相信很多人应该也看得懂):

    一旦GC决定一个“obj”是虚可达的,它(指PhantomReference)将会被入队到对应的队列,但是它的指代并没有被清除。也就是说,虚引用的引用队列一定要明确地被一些应用程序代码所处理。

    6. 弱引用与虚引用的用处

      软引用很明显可以用来制作caching和pooling,而弱引用与虚引用呢?其实用处也很大,首先我们来看看弱引用,举个例子:

    class Registry {  
        private Set registeredObjects = new HashSet();  
        public void register(Object object) {  
            registeredObjects.add( object );  
        }  
    }  

    现在如果GC想要回收registeredObjects中的object,便能够实现了,同样在使用HashMap如果想实现如上的效果,一种更好的实现是使用WeakHashMap。

    而虚引用呢?我们先来看看javadoc的部分说明:

    Phantom references are useful for implementing cleanup operations that are necessary before an object gets garbage-collected. They are sometimes more flexible than the finalize() method.

    翻译一下:

    虚引用在实现一个对象被回收之前必须做清理操作是很有用的。有时候,他们比finalize()方法更灵活。

    很明显的,虚引用可以用来做对象被回收之前的清理工作。

    PhantomReference 有两个好处, 其一, 它可以让我们准确地知道对象何时被从内存中删除, 这个特性可以被用于一些特殊的需求中(例如 Distributed GC, XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作). 

    其二, 它可以避免 finalization 带来的一些根本性问题, 上文提到 PhantomReference 的唯一作用就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中, 但是 WeakReference 也有对应的功能, 两者的区别到底在哪呢 ?
    这就要说到 Object 的 finalize 方法, 此方法将在 gc 执行前被调用, 如果某个对象重载了 finalize 方法并故意在方法内创建本身的强引用, 这将导致这一轮的 GC 无法回收这个对象并有可能
    引 起任意次 GC, 最后的结果就是明明 JVM 内有很多 Garbage 却 OutOfMemory, 使用 PhantomReference 就可以避免这个问题, 因为 PhantomReference 是在 finalize 方法执行后回收的,也就意味着此时已经不可能拿到原来的引用, 也就不会出现上述问题, 当然这是一个很极端的例子, 一般不会出现. 

    7 、一些术语:

    • 强可及对象(strongly reachable):可以通过强引用访问的对象。
    • 软可及对象(softly reachable):不是强可及对象,并且能够通过软引用访问的对象。
    • 弱可及对象(weakly reachable):不是强可及对象也不是软可及对象,并且能够通过弱引用访问的对象。
    • 虚可及对象(phantomly reachable):不是强可及对象、软可及对象,也不是弱可及对象,已经结束的,可以通过虚引用访问的对象。
    • 清除:将引用对象的 referent 域设置为 null ,并将引用类在堆中引用的对象声明为 可结束的

    参考资料:

    http://www.ibm.com/developerworks/cn/java/j-lo-langref/?ca=drs

  • 相关阅读:
    Python学习札记(十五) 高级特性1 切片
    LeetCode Longest Substring Without Repeating Characters
    Python学习札记(十四) Function4 递归函数 & Hanoi Tower
    single number和变体
    tusen 刷题
    实验室网站
    leetcode 76. Minimum Window Substring
    leetcode 4. Median of Two Sorted Arrays
    leetcode 200. Number of Islands 、694 Number of Distinct Islands 、695. Max Area of Island 、130. Surrounded Regions 、434. Number of Islands II(lintcode) 并查集 、178. Graph Valid Tree(lintcode)
    刷题注意事项
  • 原文地址:https://www.cnblogs.com/vigarbuaa/p/3007410.html
Copyright © 2011-2022 走看看