Java 中一共有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference。
一般声明都是强引用,只有在对象不可达时才会被回收。SoftReference、 WeakReference 的使用方式如下:
- String abc = new String("abc");
- final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
- WeakReference<String> abcWeakRef = new WeakReference<String>(abc,
- referenceQueue);
- abc = null;
当对象 abc 被置 null(或者内存不足)后,实际对象被自动回收,引用对象被加到 ReferenceQueue 队列中。此时调用 abcWeakRef.get() 返回 null。WeakHashMap 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry。
SoftReference 于 WeakReference 的特性基本一致, 最大的区别在于 SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收 (虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用。
PhantomReference 的 get 方法永远返回 null:
- publicTget(){
- return null;
- }
和名字一样,让人琢磨不透到底想干嘛了。同样,他也有一个引用队列,当实际对象需要被回收时,引用对象会被加入到队列中,但是,和 SoftReference 于 WeakReference 不同,幽灵引用的实际对象不会被自动回收。
- public static void main(String[] args)throwsException{
- String abc = new String("abc");
- final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
- WeakReference<String> abcWeakRef = new WeakReference<String>(abc,
- referenceQueue);
- abc = null;
- System.gc();
- Thread.currentThread().sleep(3000);
- }
以上代码在 System.gc() 之后,对象回收情况如下:
可以看到,实际对象已经被回收,引用队列里面保存着对象的引用对象,引用对象的 referent 字段也为 null。再看下 PhantomReference 的情况:
- public static void main(String[] args)throwsException{
- String abc = new String("abc");
- final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
- PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
- referenceQueue);
- abc = null;
- System.gc();
- Thread.currentThread().sleep(3000);
- }
明明已经 GC 了,可实际对象依旧没有被回收。需要手动调用引用对象的 clear 方法来回收。利用这个特效,可以用来做一些最后的清理工作。例如 ByteBuffer 的 Cleaner 对象,JVM 的 Reference Handler 线程会调用 clean() 方法。
可是,finalize 一般也是用来做一些清理性的工作,这 2 个有什么区别呢?
某论坛说:
JVM 不能保证 finalize 何时被调用, 再加上 finalize 内部可以访问对象内部的任何 field 可能导致 GC 过程混乱, 所以推荐使用 ReferenceQueue 来实现资源回收工作
我对这个观点不是很满意,希望有大神解答。
来源: http://www.tuicool.com/articles/BbUFbee