一、強(qiáng)引用
一個(gè)對(duì)象若持有強(qiáng)引用妄帘,垃圾回收器絕不會(huì)回收它楞黄。當(dāng)內(nèi)存空間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤抡驼,使程序異常終止鬼廓,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來(lái)解決內(nèi)存不足的問(wèn)題。
特點(diǎn):
- 強(qiáng)引用可以直接訪問(wèn)目標(biāo)對(duì)象婶恼。
- 強(qiáng)引用所指向的對(duì)象在任何時(shí)候都不會(huì)被系統(tǒng)回收桑阶。JVM寧愿拋出OOM異常,也不會(huì)回收強(qiáng)引用所指向的對(duì)象勾邦。
- 強(qiáng)引用可能導(dǎo)致內(nèi)存泄露蚣录。
java.lang.ref包中提供了幾個(gè)類(lèi):SoftReference、WeakReference眷篇、PhantomReference萎河,分別代表軟引用、弱引用、虛引用虐杯。
ReferenceQueue類(lèi)表示引用隊(duì)列玛歌,它可以和這三種引用類(lèi)聯(lián)合使用,以便跟蹤Java虛擬機(jī)回收所引用的對(duì)象的活動(dòng)擎椰。
二支子、軟引用(SoftReference)
軟引用是除了強(qiáng)引用外,最強(qiáng)的引用類(lèi)型达舒≈蹬螅可以通過(guò)java.lang.ref.SoftReference使用軟引用。
用法:
XXX xxx = new XXX();
SoftReference ref = new SoftReference(xxx);
XXX anotherXXX = (XXX)ref.get();
如果一個(gè)對(duì)象持有軟引用巩搏,那么如果內(nèi)存空間足夠昨登,垃圾回收器就不會(huì)回收它;如果內(nèi)存空間不足了贯底,就會(huì)回收這些對(duì)象的內(nèi)存丰辣。只要垃圾回收器沒(méi)有回收它,該對(duì)象就可以被程序使用禽捆。
軟引用可用來(lái)實(shí)現(xiàn)內(nèi)存敏感的高速緩存笙什。軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾回收胚想,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中得湘。ReferenceQueue中保存的對(duì)象是Reference對(duì)象,而且是已經(jīng)失去了它所軟引用的對(duì)象的Reference對(duì)象顿仇。
ReferenceQueue queue = new ReferenceQueue();
SoftReference ref = new SoftReference(xxx, queue);
利用ReferenceQueue.poll()方法,可以檢查哪個(gè)SoftReference所軟引用的對(duì)象已經(jīng)被回收摆马。于是可以把這些失去軟引用的對(duì)象的SoftReference對(duì)象清除掉臼闻。常用的方式為:
SoftReference ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
// 清除ref
}
示例
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
Drawable drawable = new BitmapDrawable(bitmap);
SoftReference<Drawable> drawableSoftReference = new SoftReference<Drawable>(drawable);
Drawable bgDrawable = drawableSoftReference.get();
if(bgDrawable!= null) {
view.setBackground(bgDrawable);
}
通過(guò)軟引用的get()方法,取得drawable對(duì)象實(shí)例的強(qiáng)引用囤采,發(fā)現(xiàn)對(duì)象被未回收述呐。在GC在內(nèi)存充足的情況下,不會(huì)回收軟引用對(duì)象蕉毯。
在實(shí)際中乓搬,會(huì)一起從網(wǎng)絡(luò)請(qǐng)求多個(gè)圖片,這時(shí)就會(huì)請(qǐng)求非常多的內(nèi)存空間代虾,導(dǎo)致內(nèi)存吃緊进肯,系統(tǒng)開(kāi)始GC。GC后棉磨,drawables.get()不再返回Drawable對(duì)象江掩,而是返回null,這時(shí)屏幕上背景圖不顯示,在系統(tǒng)內(nèi)存緊張的情況下环形,軟引用被回收策泣。
使用軟引用以后,在OutOfMemory異常發(fā)生之前抬吟,這些緩存的圖片資源的內(nèi)存空間可以被釋放掉的萨咕,從而避免內(nèi)存達(dá)到上限,避免Crash發(fā)生火本。
注意
在垃圾回收器對(duì)Java對(duì)象回收前危队,SoftReference類(lèi)所提供的get方法會(huì)返回Java對(duì)象的強(qiáng)引用,一旦垃圾線程回收該Java對(duì)象之后发侵,get方法將返回null交掏。所以在獲取軟引用對(duì)象的代碼中,一定要判斷是否為null刃鳄,以免出現(xiàn)NullPointerException導(dǎo)致應(yīng)用崩潰盅弛。
三、弱引用(WeakReference)
用法:
WeakReference<XXX> sr = new WeakReference<XXX>(new XXX());
如果一個(gè)對(duì)象持有弱引用叔锐,那么在垃圾回收器線程掃描的過(guò)程中挪鹏,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否愉烙,都會(huì)回收它的內(nèi)存讨盒。不過(guò),由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程步责,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象返顺。
弱引用也可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回收蔓肯,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中遂鹊。
弱引用與軟引用的根本區(qū)別:
只具有弱引用的對(duì)象擁有更短暫的生命周期,可能隨時(shí)被回收蔗包;
而只具有軟引用的對(duì)象只有當(dāng)內(nèi)存不夠的時(shí)候才被回收秉扑,在內(nèi)存足夠的時(shí)候,通常不被回收调限。
使用場(chǎng)景:
Handler中的使用舟陆,防止內(nèi)存泄露。
軟引用耻矮、弱引用都非常適合來(lái)保存那些可有可無(wú)的緩存數(shù)據(jù)秦躯。如果這樣做,當(dāng)系統(tǒng)內(nèi)存不足時(shí)裆装,這些緩存數(shù)據(jù)會(huì)被回收宦赠,不會(huì)導(dǎo)致內(nèi)存溢出陪毡。而當(dāng)內(nèi)存資源充足時(shí),這些緩存數(shù)據(jù)又可以存在相當(dāng)長(zhǎng)的時(shí)間勾扭。
如何選擇軟引用毡琉、弱引用?
- 如果只是想避免OutOfMemory異常的發(fā)生妙色,則可以使用軟引用桅滋。
- 如果對(duì)于應(yīng)用的性能更在意,想盡快回收一些占用內(nèi)存比較大的對(duì)象身辨,則可以使用弱引用丐谋。
- 還可以根據(jù)對(duì)象是否經(jīng)常使用來(lái)判斷。如果該對(duì)象可能會(huì)經(jīng)常使用的煌珊,就盡量用軟引用号俐;如果該對(duì)象不被使用的可能性更大些,就可以用弱引用定庵。
- 另外吏饿,和弱引用功能類(lèi)似的是WeakHashMap。WeakHashMap對(duì)于一個(gè)給定的鍵蔬浙,其映射的存在并不阻止垃圾回收器對(duì)該鍵的回收猪落,回收以后,其條目從映射中有效地移除畴博。WeakHashMap使用ReferenceQueue實(shí)現(xiàn)的這種機(jī)制笨忌。
四、虛引用(PhantomReference)
虛引用是所有引用類(lèi)型中最弱的一個(gè)俱病。
一個(gè)持有虛引用的對(duì)象官疲,和沒(méi)有引用幾乎是一樣的,隨時(shí)都可能被垃圾回收器回收亮隙。當(dāng)試圖通過(guò)虛引用的get()方法取得強(qiáng)引用時(shí)袁余,總是會(huì)失敗。并且咱揍,虛引用必須和引用隊(duì)列一起使用,它的作用在于跟蹤垃圾回收過(guò)程棚饵。
當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí)煤裙,如果發(fā)現(xiàn)它還有虛引用,就會(huì)在垃圾回收后噪漾,銷(xiāo)毀這個(gè)對(duì)象硼砰,將這個(gè)虛引用加入引用隊(duì)列。