全面解析Java中的GC与幽灵引用
Java 中一共有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵), 1、 Strong Reference Java代码 复制代码 代码如下: @Test 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 后 weak reference 将会被自动回收 复制代码 代码如下: @Test 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 复制代码 代码如下: @Test 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 非常适合缓存应用 复制代码 代码如下: @Test 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 作为本文主角, Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同, 因为它的 get() 方法永远返回 null,这也正是它名字的由来 Java代码 复制代码 代码如下: @Test 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 Java代码 复制代码 代码如下: @Test 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、PhantomReference vs WeakReference PhantomReference 有两个好处, 其一, 它可以让我们准确地知道对象何时被从内存中删除, 这个特性可以被用于一些特殊的需求中(例如 Distributed GC, XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作). 其二, 它可以避免 finalization 带来的一些根本性问题,上文提到 PhantomReference 的唯一作用就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中, 但是 WeakReference 也有对应的功能,两者的区别到底在哪呢 ? 7、 对比
8. 小结 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |