详见以下测试代码及其注释:
package test;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
import org.junit.Test;
class VeryBig {
private static final int SIZE = 1000;
private double[] la = new double[SIZE];
private String ident;
public VeryBig(String id) {
ident = id;
}
public VeryBig(String id, int s) {
ident = id;
la = new double[s];
}
public String toString() {
return ident;
}
protected void finalize() {
System.out.println("Finalizing " + ident);
}
}
public class ReferencesTest {
/**
* Strong Reference<br>
* 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何强引用指向对象时, GC 执行后将会回收对象
*/
@Test
public void strongReferenceNotGC() {
System.out.println("start test strongReferenceNotGC");
Object referent = new VeryBig("strongReferenceNotGC");
/**
* 通过赋值创建 StrongReference
*/
Object strongReference = referent;
assertSame(referent, strongReference);
referent = null;
System.gc();
/**
* 由于对象还存在引用,因此gc后,对象未被回收
*/
assertNotNull(strongReference);
System.out.println("end test strongReferenceNotGC");
}
@Test
public void strongReferenceGC() throws InterruptedException {
System.out.println("start test strongReferenceGC");
Object referent = new VeryBig("strongReferenceGC");
referent = null;
System.gc();
Thread.sleep(500);
System.out.println("end test strongReferenceGC");
}
/**
* WeakReference<br>
* 顾名思义, 是一个弱引用, 当所引用的对象在 JVM 内不再有强引用时, GC后,弱引用被置成null,并回收所指的对象
*
* @throws InterruptedException
*/
@Test
public void weakReference() throws InterruptedException {
System.out.println("start test weakReference");
WeakReference<Object> weakRerference = new WeakReference<Object>(new VeryBig(
"weakReference"));
System.gc();
Thread.sleep(500);
/**
* weak reference 在 GC 后会被置成null,对象就可以被 回收了。。。
*/
assertNull(weakRerference.get());
System.out.println("end test weakReference");
}
/**
* WeakHashMap<br>
* 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的
* entry
*
* @throws InterruptedException
*/
@Test
public void weakHashMap() throws InterruptedException {
Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();
Object key = new VeryBig("weakHashMap key");
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));
}
/**
* SoftReference<br>
* 与 WeakReference 的特性基本一致, 最大的区别在于
* SoftReference会尽可能长的保留引用,不会在GC时就回收对象,而是直到 JVM 内存不足时才会被回收(虚拟机保证),
* 这一特性使得 SoftReference 非常适合缓存应用
*/
@Test
public void softReference() {
SoftReference<Object> softRerference = new SoftReference<Object>(new VeryBig(
"softReference"));
assertNotNull(softRerference.get());
System.gc();
/**
* soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用
*/
assertNotNull(softRerference.get());
// make oom....
int i = 0;
while (true) {
try {
++i;
new VeryBig("oom ", 10000000);
} catch (Throwable e) {
System.out.println("OOM after " + i + " times");
e.printStackTrace();
break;
}
}
assertNull(softRerference.get());
}
/**
* PhantomReference<br>
* Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同, 因为它的
* get() 方法永远返回 null, 这也正是它名字的由来
*/
@Test
public void phantomReferenceAlwaysNull() {
ReferenceQueue<Object> q = new ReferenceQueue<Object>();
PhantomReference<Object> phantomReference = new PhantomReference<Object>(
new VeryBig("phantomReferenceAlwaysNull"), q);
/**
* phantom reference 的 get 方法永远返回 null
*/
assertNull(phantomReference.get());
assertNull(q.poll());
System.gc();
assertNull(q.poll());
}
/**
* RererenceQueue<br>
* 当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个
* ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个weak ref插入到
* ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的
* entries
*
* @throws InterruptedException
*/
@Test
public void referenceQueueWithWeakReference() throws InterruptedException {
Object referent = new VeryBig("referenceQueueWithWeakReference");
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
Reference<Object> ref = new WeakReference<Object>(referent, referenceQueue);
assertFalse(ref.isEnqueued());
Reference<? extends Object> polled = referenceQueue.poll();
assertNull(polled);
referent = null;
System.gc();
assertTrue(ref.isEnqueued());
Reference<? extends Object> removed = referenceQueue.remove();
assertNotNull(removed);
assertSame(ref, removed);
assertNull(removed.get());
}
@Test
public void referenceQueueWithSoftReference() throws InterruptedException {
Object referent = new VeryBig("referenceQueueWithWeakReference");
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
Reference<Object> ref = new SoftReference<Object>(referent, referenceQueue);
assertFalse(ref.isEnqueued());
Reference<? extends Object> polled = referenceQueue.poll();
assertNull(polled);
referent = null;
// make oom....
try {
new VeryBig("oom ", 100000000);
} catch (Throwable e) {
}
assertTrue(ref.isEnqueued());
Reference<? extends Object> removed = referenceQueue.remove();
assertNotNull(removed);
assertSame(ref, removed);
assertNull(removed.get());
}
}
参考:
http://www.iteye.com/topic/401478