學會使用軟引用和弱引用可以進一步優化內存泄漏問題。
本文主要讓大家瞭解什麼叫強引用
、軟引用
、弱引用
、虛引用
以及怎麼使用。
(1)強引用(StrongReference)
Object object = new Object();
String name= "zhangsan";
強引用在項目中很常見,程序猿已經習慣性的使用強引用了,以上兩句簡單代碼就是所謂的強引用。
當強引用對象佔用的內存超過最大可分配內存時,就是發生OOM。
(2)軟引用(SoftReference)
軟引用是用來描述一些有用但並不是必需的對象,在Java中用java.lang.ref.SoftReference類來表示。對於軟引用關聯着的對象,只有在內存不足的時候JVM纔會回收該對象。因此,這一點可以很好地用來解決OOM的問題,並且這個特性很適合用來實現緩存:比如網頁緩存、圖片緩存等。
SoftReference<String> str1 = new SoftReference<>(new String("hello1"));
Log.d("aaa", "str:"+str1.get());
//可以將軟引用存入引用隊列
ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
SoftReference<String> str2 = new SoftReference<>(new String("hello2"), referenceQueue);
Log.d("aaa", "str:"+str2.get());
(3)弱引用(WeakReference)
弱引用也是用來描述非必需對象的,當JVM進行垃圾回收時,無論內存是否充足,都會回收被弱引用關聯的對象。在java中,用java.lang.ref.WeakReference類來表示。
WeakReference<String> str = new WeakReference<>(new String("hello"));
Log.d("aaa", "str:"+str.get());
System.gc();
Log.d("aaa", "str:"+str.get());
結果爲:
(4)虛引用(PhantomReference)
虛引用和前面的軟引用、弱引用不同,它並不影響對象的生命週期。在java中用java.lang.ref.PhantomReference類表示。如果一個對象與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收。
要注意的是,虛引用必須和引用隊列關聯使用,當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會把這個虛引用加入到與之 關聯的引用隊列中。程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取必要的行動。
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> str = new PhantomReference<>(new String("hello"), queue);
Log.d("aaa", "str:"+str.get());
結果是:
(5)如何使用軟引用解決OOM問題
BitmapFactory.decodeFile()
將圖片轉成bitmap,這句代碼是非常消耗性能的,爲了防止同一張圖片頻繁的轉成bitmap,我們需要將bitmap存入緩存,代碼如下:
private Map<String, Bitmap> bitmaps = new HashMap();
/**
* 將Bitmap保存到緩存
* @param path 文件路徑
* @param bitmap 文件的bitmap對象
*/
private void addBitmapToCache(String path, Bitmap bitmap){
bitmaps.put(path, bitmap);
}
/**
* 獲取緩存中的bitmap
* @param path
* @return
*/
private Bitmap getBitmap(String path){
Bitmap bitmap = bitmaps.get(path);
return bitmap;
}
這個想法不錯,但是bitmap是非常佔用內存的,如果緩存容器中存放多個bitmap對象很有可能造成OOM問題,解決OOM問題需要引用軟引用
或者弱引用
,軟引用
只有在內存不足的時候JVM纔會回收該對象,弱引用
無論內存是否充足,JVM進行垃圾回收時,都會回收被關聯的對象。這裏採用軟引用
較爲適合。
private Map<String, SoftReference<Bitmap>> bitmaps = new HashMap();
/**
* 將Bitmap保存到緩存
* @param path 文件路徑
* @param bitmap 文件的bitmap對象
*/
private void addBitmapToCache(String path, Bitmap bitmap){
bitmaps.put(path, new SoftReference<Bitmap>(bitmap));
}
/**
* 獲取緩存中的bitmap
* @param path
* @return
*/
private Bitmap getBitmap(String path){
//獲取軟引用
SoftReference<Bitmap> softReference = bitmaps.get(path);
if(softReference == null){
return null;
}
Bitmap bitmap = softReference.get();
return bitmap;
}
以上代碼是一個不錯的方案,當獲取的bitmap爲null時,就重新在本地解碼圖片。