簡(jiǎn)介:
本文主要介紹JAVA中的四種引用: StrongReference(強(qiáng)引用)惋鸥、SoftReferenc(軟引用)募谎、WeakReferenc(弱引用)、PhantomReference(虛引用)的作用智什。同時(shí)我們還將介紹ReferenceQueue和WeakHashMap的功能和使用示例持灰。
歡迎探討,如有錯(cuò)誤敬請(qǐng)指正
如需轉(zhuǎn)載嗓化,請(qǐng)注明出處 http://www.cnblogs.com/nullzx/
1. JAVA中的四種引用
四種引用中棠涮,軟引用、若引用刺覆、虛引用都需要相關(guān)類來創(chuàng)建严肪。創(chuàng)建的時(shí)候都需要傳遞一個(gè)對(duì)象,然后通過引用的get方法獲取真正的對(duì)象谦屑。
1.1 StrongReference(強(qiáng)引用)
強(qiáng)引用就是我們一般在程序中引用一個(gè)對(duì)象的方式
Object obj = new Object();
obj就是一個(gè)強(qiáng)引用驳糯。垃圾回收器絕不會(huì)回收它,當(dāng)內(nèi)存空間不足氢橙,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤酝枢,使程序異常終止,也不會(huì)靠回收具有強(qiáng)引用的對(duì)象來解決內(nèi)存不足的問題悍手。
SoftReference(軟引用)
軟引用的創(chuàng)建要借助于java.lang.ref包下的SoftReferenc類帘睦。當(dāng)JVM進(jìn)行垃圾回收時(shí),只有在內(nèi)存不足的時(shí)候JVM才會(huì)回收僅有軟引用指向的對(duì)象所占的空間坦康。
軟引用的創(chuàng)建要借助于java.lang.ref包下的SoftReferenc類竣付。當(dāng)JVM進(jìn)行垃圾回收時(shí),只有在內(nèi)存不足的時(shí)候JVM才會(huì)回收僅有軟引用指向的對(duì)象所占的空間滞欠。
package javalearning;
import java.lang.ref.SoftReference;
/*
* 虛擬機(jī)參數(shù)配置
* -Xms256m
* -Xmx1024m
*/
public class SoftReferenceDemo {
public static void main(String[] args){
/*軟引用對(duì)象中指向了一個(gè)長(zhǎng)度為300000000個(gè)元素的整形數(shù)組*/
SoftReference<int[]> softReference =
new SoftReference<int[]>(new int[300000000]);
/*主動(dòng)調(diào)用一次gc,由于此時(shí)JVM的內(nèi)存夠用古胆,此時(shí)softReference引用的對(duì)象未被回收*/
System.gc();
System.out.println(softReference.get());
/*消耗內(nèi)存,會(huì)導(dǎo)致一次自動(dòng)的gc,此時(shí)JVM的內(nèi)存不夠用
*就回收softReference對(duì)象中指向的數(shù)組對(duì)象*/
int[] strongReference = new int[100000000];
System.out.println(softReference.get());
}
}
我們應(yīng)該注意到,上面的代碼中名為softReference的引用指向了一個(gè)
SoftReference對(duì)象筛璧,這個(gè)指向還是一個(gè)強(qiáng)引用類型逸绎。而SoftReference對(duì)象中指向int類型數(shù)組的引用就是一個(gè)軟引用類型了惹恃。
運(yùn)行結(jié)果
[I@2a139a55
null
1.3 WeakReference(弱引用)
弱引用的創(chuàng)建要借助于java.lang.ref包下的WeakReferenc類。當(dāng)JVM進(jìn)行垃圾回收時(shí)棺牧,無論內(nèi)存是否充足巫糙,都會(huì)回收僅被弱引用關(guān)聯(lián)的對(duì)象。由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程陨帆,因此不一定會(huì)很快發(fā)現(xiàn)那些被弱引用指向的對(duì)象曲秉。
package javalearning;
import java.lang.ref.WeakReference;
public class WeakReferenceDemo {
public static void main(String[] args){
/*若引用對(duì)象中指向了一個(gè)長(zhǎng)度為1000個(gè)元素的整形數(shù)組*/
WeakReference<String[]> weakReference =
new WeakReference<String[]>(new String[1000]);
/*未執(zhí)行g(shù)c,目前僅被弱引用指向的對(duì)象還未被回收,所以結(jié)果不是null*/
System.out.println(weakReference.get());
/*執(zhí)行一次gc,即使目前JVM的內(nèi)存夠用,但還是回收僅被弱引用指向的對(duì)象*/
System.gc();
System.out.println(weakReference.get());
}
}
同理疲牵,上面的代碼中名為weakReference的引用指向了一個(gè)
WeakReference對(duì)象承二,這個(gè)指向還是一個(gè)強(qiáng)引用類型。而WeakReference對(duì)象中指向String類型數(shù)組的引用就是一個(gè)弱引用類型了纲爸。
運(yùn)行結(jié)果
[Ljava.lang.String;@2a139a55
null
1.4 PlantomReference(虛引用)
如果一個(gè)對(duì)象僅持有虛引用亥鸠,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收识啦。創(chuàng)建一個(gè)虛引用對(duì)象時(shí)必須還要傳遞一個(gè)引用隊(duì)列(ReferenceQueue)负蚊。
2. ReferenceQueue(引用隊(duì)列)簡(jiǎn)介
當(dāng)gc(垃圾回收線程)準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還僅有軟引用(或弱引用颓哮,或虛引用)指向它家妆,就會(huì)在回收該對(duì)象之前,把這個(gè)軟引用(或弱引用冕茅,或虛引用)加入到與之關(guān)聯(lián)的引用隊(duì)列(ReferenceQueue)中伤极。如果一個(gè)軟引用(或弱引用,或虛引用)對(duì)象本身在引用隊(duì)列中姨伤,就說明該引用對(duì)象所指向的對(duì)象被回收了哨坪。
當(dāng)軟引用(或弱引用,或虛引用)對(duì)象所指向的對(duì)象被回收了乍楚,那么這個(gè)引用對(duì)象本身就沒有價(jià)值了当编,如果程序中存在大量的這類對(duì)象(注意,我們創(chuàng)建的軟引用徒溪、弱引用忿偷、虛引用對(duì)象本身是個(gè)強(qiáng)引用,不會(huì)自動(dòng)被gc回收)臊泌,就會(huì)浪費(fèi)內(nèi)存鲤桥。因此我們這就可以手動(dòng)回收位于引用隊(duì)列中的引用對(duì)象本身。
除了上面代碼展示的創(chuàng)建引用對(duì)象的方式缺虐。軟芜壁、弱礁凡、虛引用的創(chuàng)建還有另一種方式高氮,即在創(chuàng)建引用的同時(shí)關(guān)聯(lián)一個(gè)引用隊(duì)列慧妄。
SoftReference(T referent, ReferenceQueue<? super T> q)
WeakReference(T referent, ReferenceQueue<? super T> q)
PhantomReference(T referent, ReferenceQueue<? super T> q)
下面的示例中我們利用ReferenceQueue回收SoftReference對(duì)象本身。
package javalearning;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
public class ReferenceQueneDemo {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args){
/*創(chuàng)建引用隊(duì)列*/
ReferenceQueue<SoftReference<int[]>> rq =
new ReferenceQueue<SoftReference<int[]>>();
/*創(chuàng)建一個(gè)軟引用數(shù)組剪芍,每一個(gè)對(duì)象都是軟引用類型*/
SoftReference<int[]>[] srArr = new SoftReference[1000];
for(int i = 0; i < srArr.length; i++){
srArr[i] = new SoftReference(new int[300000], rq);
}
/*(可能)在gc前保留下了三個(gè)強(qiáng)引用*/
int[] arr1 = srArr[30].get();
int[] arr2 = srArr[60].get();
int[] arr3 = srArr[90].get();
/*占用內(nèi)存塞淹,會(huì)導(dǎo)致一次gc,使得只有軟引用指向的對(duì)象被回收*/
int[] strongRef = new int[200000000];
Object x;
int n = 0;
while((x = rq.poll()) != null){
int idx = 0;
while(idx < srArr.length){
if(x == srArr[idx]){
System.out.println("free " + x);
srArr[idx] = null; /*手動(dòng)釋放內(nèi)存*/
n++;
break;
}
idx++;
}
}
/*當(dāng)然最簡(jiǎn)單的方法是通過isEnqueued()判斷一個(gè)軟引用方法是否在
* 隊(duì)列中罪裹,上面的方法只是舉例
int n = 0;
for(int i = 0; i < srArr.length; i++){
if(srArr[i].isEnqueued()){
srArr[i] = null;
n++;
}
}
*/
System.out.println("recycle " + n + " SoftReference Object");
}
}
運(yùn)行結(jié)果(省略部分結(jié)果)
……
……
……
free java.lang.ref.SoftReference@cc285f4
free java.lang.ref.SoftReference@55f3ddb1
free java.lang.ref.SoftReference@8bd1b6a
free java.lang.ref.SoftReference@18be83e4
free java.lang.ref.SoftReference@cb5822
recycle 997 SoftReference Object
從上面的例子中可以看出饱普,我們回收SoftReference對(duì)象的效率并不高。原因是每從隊(duì)列中取出一個(gè)SoftReference引用状共,就是我們必須和SoftReference[]數(shù)組中的每一個(gè)對(duì)象逐個(gè)比較套耕。這樣的查找方式顯然不及HashMap,所以我們自然想到構(gòu)建一個(gè)引用類型的HashMap來解決這個(gè)問題峡继。而實(shí)際上JDK中已經(jīng)提供了一個(gè)具有這樣功能的類冯袍,即WeakHashMap。