Java從JDK1.2版本開(kāi)始,就把對(duì)象的引用分為四種級(jí)別,從而使程序能更加靈活的控制對(duì)象的生命周期。這四種級(jí)別由高到低依次為:強(qiáng)引用、軟引用、弱引用和虛引用。
這里重點(diǎn)介紹一下軟引用和弱引用。
如果一個(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ì)列中。
如果一個(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í)候,通常不被回收。
在java.lang.ref包中提供了幾個(gè)類:SoftReference類、WeakReference類和PhantomReference類,它們分別代表軟引用、弱引用和虛引用。ReferenceQueue類表示引用隊(duì)列,它可以和這三種引用類聯(lián)合使用,以便跟蹤Java虛擬機(jī)回收所引用的對(duì)象的活動(dòng)。
在Android應(yīng)用的開(kāi)發(fā)中,為了防止內(nèi)存溢出,在處理一些占用內(nèi)存大而且聲明周期較長(zhǎng)的對(duì)象時(shí)候,可以盡量應(yīng)用軟引用和弱引用技術(shù)。
下面以使用軟引用為例來(lái)詳細(xì)說(shuō)明。弱引用的使用方式與軟引用是類似的。
假設(shè)我們的應(yīng)用會(huì)用到大量的默認(rèn)圖片,比如應(yīng)用中有默認(rèn)的頭像,默認(rèn)游戲圖標(biāo)等等,這些圖片很多地方會(huì)用到。如果每次都去讀取圖片,由于讀取文件需要硬件操作,速度較慢,會(huì)導(dǎo)致性能較低。所以我們考慮將圖片緩存起來(lái),需要的時(shí)候直接從內(nèi)存中讀取。但是,由于圖片占用內(nèi)存空間比較大,緩存很多圖片需要很多的內(nèi)存,就可能比較容易發(fā)生OutOfMemory異常。這時(shí),我們可以考慮使用軟引用技術(shù)來(lái)避免這個(gè)問(wèn)題發(fā)生。
首先定義一個(gè)HashMap,保存軟引用對(duì)象。
private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>(); |
再來(lái)定義一個(gè)方法,保存Bitmap的軟引用到HashMap。
public void addBitmapToCache(String path) { // 強(qiáng)引用的Bitmap對(duì)象 Bitmap bitmap = BitmapFactory.decodeFile(path); // 軟引用的Bitmap對(duì)象 SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap); // 添加該對(duì)象到Map中使其緩存 imageCache.put(path, softBitmap); }
|
獲取的時(shí)候,可以通過(guò)SoftReference的get()方法得到Bitmap對(duì)象。
public Bitmap getBitmapByPath(String path) { // 從緩存中取軟引用的Bitmap對(duì)象 SoftReference<Bitmap> softBitmap = imageCache.get(path); // 判斷是否存在軟引用 if (softBitmap == null) { return null; } // 取出Bitmap對(duì)象,如果由于內(nèi)存不足Bitmap被回收,將取得空 Bitmap bitmap = softBitmap.get(); return bitmap; } |
使用軟引用以后,在OutOfMemory異常發(fā)生之前,這些緩存的圖片資源的內(nèi)存空間可以被釋放掉的,從而避免內(nèi)存達(dá)到上限,避免Crash發(fā)生。
需要注意的是,在垃圾回收器對(duì)這個(gè)Java對(duì)象回收前,SoftReference類所提供的get方法會(huì)返回Java對(duì)象的強(qiáng)引用,一旦垃圾線程回收該Java對(duì)象之后,get方法將返回null。所以在獲取軟引用對(duì)象的代碼中,一定要判斷是否為null,以免出現(xiàn)NullPointerException異常導(dǎo)致應(yīng)用崩潰。
經(jīng)驗(yàn)分享: 到底什么時(shí)候使用軟引用,什么時(shí)候使用弱引用呢? 個(gè)人認(rèn)為,如果只是想避免OutOfMemory異常的發(fā)生,則可以使用軟引用。如果對(duì)于應(yīng)用的性能更在意,想盡快回收一些占用內(nèi)存比較大的對(duì)象,則可以使用弱引用。 還有就是可以根據(jù)對(duì)象是否經(jīng)常使用來(lái)判斷。如果該對(duì)象可能會(huì)經(jīng)常使用的,就盡量用軟引用。如果該對(duì)象不被使用的可能性更大些,就可以用弱引用。 另外,和弱引用功能類似的是WeakHashMap。WeakHashMap對(duì)于一個(gè)給定的鍵,其映射的存在并不阻止垃圾回收器對(duì)該鍵的回收,回收以后,其條目從映射中有效地移除。WeakHashMap使用ReferenceQueue實(shí)現(xiàn)的這種機(jī)制 |
聯(lián)系客服