1,強引用:
package com.myjava.reference;
/**
* ①強引用不會被垃圾回收器自動回收
* ②當記憶體空間不足時,Java虛拟機甯可抛出OutOfMemoryError錯誤,也不會随意回收強引用對象來解決記憶體不足問題
* @author Administrator
*
*/
public class TestStrongReference {
public static void main(String[] args) {
Object ref = new Object();
Object strongRef = ref;
System.gc();
System.out.println(strongRef!=null?"StrongRef not gc":"StrongRef is gc");
}
-------------------------------------------------------------------------------------------------------------------------------
2,軟引用;
import java.lang.ref.SoftReference;
* ①,softReference 軟引用在記憶體充足時不會被GC,
* ②,當記憶體空間不足時就會回收這些對象的記憶體
* ③,适合做高速通路,如cache--Android開發中
public class TestSoftReference {
String str = "test soft GC";
SoftReference<String> softReference = new SoftReference<String>(str);
str = null;
System.out.println(softReference.get() != null ? "softReference not gc"
: "softReference is gc");
----------------------------------------------------------------------------------------------------------
弱引用:
import java.lang.ref.WeakReference;
* ①,不管目前記憶體空間足夠與否,都會回收它的記憶體。
* ②,結合ReferenceQueue可以讓程式在第一時間得到referent被回收的事件
* ③,一般用來防止記憶體洩漏,要保證記憶體被VM回收
public class TestWeakReference {
String str = "test weakReference " ;
WeakReference < String > weakReference = new WeakReference <String>(str);
str = null;
System.gc();
System.out.println(weakReference.get()!= null? "weakReference not gc": "weakReference is gc");
javascript:void(0)
http://zhangjunhd.blog.51cto.com/113473/53092/
-----------------------------------------------------------------------------------------------------------------
4,虛引用
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
public class TestPhantomReference {
public static void main(String[] args) {
ReferenceQueue referenceQueue = new ReferenceQueue();
Object object = new Object() {
public String toString() {
return "Referenced Object";
}
};
Object data = new Object() {
return "Data";
HashMap map = new HashMap();
Reference reference = null;
System.out.println("Testing PhantomReference.");
reference = new PhantomReference(object, referenceQueue);
map.put(reference, data);
System.out.println(reference.get()); // null
System.out.println(map.get(reference)); // Data
System.out.println(reference.isEnqueued()); // false
System.gc();
object = null;
data = null;
System.out.println(reference.isEnqueued()); // true, because object has been reclaimed.
}
Strong Reference, 強引用,即java标準的引用方式,表示GC從 Root Set 開始向下掃描,可以找到對應的 Strong Reference。
Referent,被包裝為 Weak, Soft, Phantom Reference的對象引用稱之為 referent。後面的内容會多次提到這個名詞。
Weak Reference, 弱引用。當一個referent,在運作時沒有同時被強,軟引用,隻被Weak Reference自身引用,且Weak Reference從 Root Set 可達,則該referent會被GC回收。
WR的作用,一般是為referent提供一個被回收的憑據,結合ReferenceQueue可以讓程式在第一時間得到referent被回收的事件,進而做一些額外的clean操作。(如果對ReferenceQueue作用和回調感興趣,可以先看最下面的 ReferenceQueue 簡介)
Soft Reference, 軟引用。它是除strong外,生命周期最長的一種 Reference,隻有當JVM Heap中充滿Strong References, Full GC無法為heap騰出更多空間而即将抛出OOM時,SoftReferences會被GC回收。
SR的作用一般是用作不限大小的 cache(無需remove)。
比如将其 Soft Reference 無限地放入 hashmap 中,而不關心hashmap内的對象數量是否會撐爆heap,也不需要手動 remove。
當Heap容量達到OOM觸發條件時,VM會自動回收該map裡的所有SoftReferences.
Phanton Reference, 是一種特殊的Reference,正如他的名字所表達的,幻影引用,他可以像幻影一樣附着在referent上。
當GC在周遊引用關系時,如果發現被phantom reference包裝過的referent不存在strong, weak, soft引用時(就是除phantom外沒有任何引用,幻影的由來),GC會将 phantom reference 放入 Reference queue。以便程式在另一邊通過queue的remove/poll方法,感覺referent被GC回收的事件。(如果對 ReferenceQueue作用和回調感興趣,可以先看最下面 ReferenceQueue 簡介)
另外,我們知道,GC在回收對象前會先調用對象自身的finalize()方法,如果它有實作的話,然後再清掉記憶體。而Phantom Reference的回調(enqueue)是在對象的finalize後,回收前觸發。這跟 WeakReference不一樣。WR是在回收後才通知的。在這個特殊的階段可以做一些特殊的clean操作。
為什麼 Phantom Reference 的get總是傳回null?
因為phantom reference想做到幻影(除自身外,不跟其他任何引用有關聯),是以不允許程式能通過自身的get方法得到referent,而破壞幻影的初衷。
執行個體代碼
package com.kenwublog.reference;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
public class PhantomReferenceTest {
public static void main(String[] args) {
ReferenceQueue referenceQueue = new ReferenceQueue();
Object object = new Object() {
public String toString() {
return "Referenced Object";
}
};
Object data = new Object() {
public String toString() {
return "Data";
}
};
HashMap map = new HashMap();
Reference reference = null;
System.out.println("Testing PhantomReference.");
reference = new PhantomReference(object, referenceQueue);
map.put(reference, data);
System.out.println(reference.get()); // null
System.out.println(map.get(reference)); // Data
System.out.println(reference.isEnqueued()); // false
System.gc();
System.out.println(reference.get()); // null
System.out.println(map.get(reference)); // Data
System.out.println(reference.isEnqueued()); // false
object = null;
data = null;
System.gc();
System.out.println(reference.get()); // null
System.out.println(map.get(reference)); // Data
System.out.println(reference.isEnqueued()); // true, because object has been reclaimed.
}
}
ReferenceQueue,一種當 weak, soft, phantom的referent被GC回收後,提供事件回調的接口。需要在執行個體化三大reference時,通過構造函數傳入,phantom reference是強制需要傳入的,weak和soft可不傳。
回調過程:
GC回收referent後(phantom是在回收前,finalize後),将reference enqueue到RQ中,程式通過調用RQ的remove方法來感覺reference被GC回收的事件。
remove方法是阻塞的,當沒有referent被回收時(GC未調用enqueue),remove方法會一直挂起線程,當有referent被回收時,該方法傳回 referent對應的reference對象。
同樣,RQ也提供了一個非阻塞的方法 poll,但這樣就做不到實時回調了。
執行個體
package com.kenwublog.reference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class ReferenceQueueTest {
public static void main(String[] args) {
final ReferenceQueue q = new ReferenceQueue();
String str = new String("AK47");
WeakReference wr = new WeakReference(str, q);
Thread t = new Thread(){
@Override
public void run() {
try {
Reference reference = q.remove();
System.out.println(reference + " event fired.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.setDaemon(true);
t.start();
System.out.println("Reference Queue is listening.");
str = null; // clear strong reference
System.out.println("Ready to gc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wr.get: " + wr.get());
}
}