理解 Java 的 GC 与 引用

Java中一共有4种类型的引用:StrongReference、SoftReference、WeakReference以及PhantomReference;这4种类型的引用与GC有着密切的关系,让咱们逐一来看它们的定义和使用场景:

1.StrongReference

StrongReference是Java的默认引用实现,它会尽量长时间的存活于JVM内,当没有任何对象指向它时GC执行后将会被回收  html

public void strongReference() {
        Object referent = new Object();
        // 经过赋值建立 StrongReference
        Object strongReference = referent;
        assertSame(referent, strongReference);
        referent = null;
        System.gc();
        // StrongReference 在 GC 后不会被回收
        assertNotNull(strongReference);
    }

2.WeakReference&WeakHashMap

WeakReference,顾名思义,是一个弱引用,当所引用的对象在JVM内再也不有强引用时,GC后weakreference将会被自动回收 
public void weakReference() {
        Object referent = new Object();
        WeakReference<Object> weakRerference = new WeakReference<Object>(referent);
        assertSame(referent, weakRerference.get());
        referent = null;
        System.gc();
        // 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回
        assertNull(weakRerference.get());
    }
WeakHashMap使用WeakReference做为key,一旦没有指向key的强引用,WeakHashMap在GC后将自动删除相关的entry
public void weakHashMap() throws InterruptedException {
        Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();
        Object key = new Object();
        Object value = new Object();
        weakHashMap.put(key, value);
        assertTrue(weakHashMap.containsValue(value));
        key = null;
        System.gc();
        // 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理
        Thread.sleep(1000);
        // 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry
        assertFalse(weakHashMap.containsValue(value));
    }

3.SoftReference

SoftReference于WeakReference的特性基本一致,最大的区别在于SoftReference会尽量长的保留引用直到JVM内存不足时才会被回收(虚拟机保证),这一特性使得SoftReference很是适合缓存应用 
public void softReference() {
        Object referent = new Object();
        SoftReference<Object> softRerference = new SoftReference<Object>(referent);
        assertNotNull(softRerference.get());
        referent = null;
        System.gc();
        // soft references 只有在 jvm OutOfMemory 以前才会被回收, 因此它很是适合缓存应用
        assertNotNull(softRerference.get());
    }

4.PhantomReference

PhantomReference(幽灵引用)与WeakReference和SoftReference有很大的不一样,由于它的get()方法永远返回null,这也正是它名字的由来 
public void phantomReferenceAlwaysNull() {
        Object referent = new Object();
        PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>());
        // phantom reference 的 get 方法永远返回 null
        assertNull(phantomReference.get());
    }
诸位可能要问,一个永远返回null的reference要来何用,请注意构造PhantomReference时的第二个参数ReferenceQueue(事实上WeakReference&SoftReference也能够有这个参数),PhantomReference惟一的用处就是跟踪referent什么时候被enqueue到ReferenceQueue中.

5.RererenceQueue

当一个WeakReference开始返回null时,它所指向的对象已经准备被回收,这时能够作一些合适的清理工做.将一个ReferenceQueue传给一个Reference的构造函数,当对象被回收时,虚拟机会自动将这个对象插入到ReferenceQueue中,WeakHashMap就是利用ReferenceQueue来清除key已经没有强引用的entries. 
public void referenceQueue() throws InterruptedException {
        Object referent = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
        WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue);
        assertFalse(weakReference.isEnqueued());
        Reference<? extends Object> polled = referenceQueue.poll();
        assertNull(polled);
        referent = null;
        System.gc();
        assertTrue(weakReference.isEnqueued());
        Reference<? extends Object> removed = referenceQueue.remove();
        assertNotNull(removed);
    }

6.PhantomReferencev&WeakReference

PhantomReference有两个好处,其一,它可让咱们准确地知道对象什么时候被从内存中删除,这个特性能够被用于一些特殊的需求中(例如DistributedGC,XWork和google-guice中也使用PhantomReference作了一些清理性工做).其二,它能够避免finalization带来的一些根本性问题,上文提到PhantomReference的惟一做用就是跟踪referent什么时候被enqueue到ReferenceQueue中,可是WeakReference也有对应的功能,二者的区别到底在哪呢?这就要说到Object的finalize方法,此方法将在gc执行前被调用,若是某个对象重载了finalize方法并故意在方法内建立自己的强引用,这将致使这一轮的GC没法回收这个对象并有可能引发任意次GC,最后的结果就是明明JVM内有不少Garbage却OutOfMemory,使用PhantomReference就能够避免这个问题,由于PhantomReference是在finalize方法执行后回收的,也就意味着此时已经不可能拿到原来的引用,也就不会出现上述问题,固然这是一个很极端的例子,通常不会出现.

7.对比

taken from http://mindprod.com/jgloss/phantom.html
Soft vs Weak vs Phantom References Type Purpose Use When GCed Implementing Class
Strong Reference
An ordinary reference. Keeps objects alive as long as they are referenced.
normal reference.
Any object not pointed to can be reclaimed.
default
Soft Reference
Keeps objects alive provided there’s enough memory.
to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key.
After a first gc pass, the JVM decides it still needs to reclaim more space.
java.lang.ref.SoftReference
Weak Reference
Keeps objects alive only while they’re in use (reachable) by clients.
Containers that automatically delete objects no longer in use.
After gc determines the object is only weakly reachable
java.lang.ref.WeakReference 
java.util.WeakHashMap
Phantom Reference Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use offinalize()) Special clean up processing
After finalization.
java.lang.ref.PhantomReference
相关文章
相关标签/搜索