Android 性能優化之巧用軟引用與弱引用優化內存使用
前言:
從事Android開發的同學都知道移動設備的內存使用是非常敏感的話題,今天我們來看下如何使用軟引用與弱引用來優化內存使用。下面來理解幾個概念。
1.StrongReference(強引用)
強引用是我們最最常見的一種,一般我們在代碼中直接通過new出來的對象等,都是強引用,強引用只要存在沒有被銷毀,內存就不會被系統回收。我們以生成Bitmap為例如下:
Bitmap imageBitmap = readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5);
生成Bitmap代碼:
public Bitmap readBitmapFromResource(Resources resources, int resourcesId) {
BitmapFactory.Options options = new BitmapFactory.Options();
return BitmapFactory.decodeResource(resources, resourcesId, options);
}
2.SoftReference(軟引用)
軟引用是用來描述一些有用但并不是必需的對象,在內存嚴重不足的情況下會被系統回收,如果該對象可能會經常使用的,就盡量用軟引用。因此,這一點可以很好地用來解決OOM的問題,并且這個特性很適合用來實現緩存:比如網頁緩存、圖片緩存等。這里還是以緩存Bitmap為例:
SoftReference<Bitmap> softReference = new SoftReference<Bitmap>(readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5));
Bitmap bitmap = softReference.get();
3.WeakReference(弱引用)
弱引用也是用來描述非必需對象的,當JVM進行垃圾回收時,無論內存是否充足,都會回收被弱引用關聯的對象,WeakReference 的強度又明顯低于 SoftReference,所以如果該對象不被使用的可能性更大些,就可以用弱引用。還是以緩存Bitmap為例:
WeakReference<Bitmap> weakReference = new WeakReference<Bitmap>(readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5));
Bitmap bitmap1 = weakReference.get();
4.PhantomReference(虛引用)
虛引用和前面的軟引用、弱引用不同,它并不影響對象的生命周期。如果一個對象與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收。還是以緩存Bitmap為例:
ReferenceQueue<Bitmap> queue = new ReferenceQueue<Bitmap>();
PhantomReference<Bitmap> phantomReference = new PhantomReference<Bitmap>(readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5),queue);
Bitmap bitmap2 = phantomReference.get();
5.幾種引用被回收概念測試
從上面的分析可以看出內存被系統回收的概率從小到大是: 虛引用--弱引用--軟引用--強引用 ,我們寫個程序來驗證一下。
public class MainActivity extends AppCompatActivity {
private LinearLayout request_layout;
private PhantomReference<Bitmap> phantomReference;
private WeakReference<Bitmap> weakReference;
private SoftReference<Bitmap> softReference;
private Bitmap strongReference;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
request_layout = (LinearLayout) findViewById(R.id.request_layout);
findViewById(R.id.request_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testReference();
}
});
}
private void testReference() {
//模擬內存使用 往一個布局中不斷加入ImageView來模擬內存使用
ImageView imageView = new ImageView(this);
Bitmap imageBitmap = readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5);
imageView.setImageBitmap(imageBitmap);
request_layout.addView(imageView);
if (strongReference == null) {
strongReference = readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5);
}
Log.e("Reference", "StrongReference---->" + strongReference);
if (softReference == null) {
softReference = new SoftReference<Bitmap>(readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5));
}
Bitmap bitmap = softReference.get();
Log.e("Reference", "SoftReference---->" + bitmap);
if (weakReference == null) {
weakReference = new WeakReference<Bitmap>(readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5));
}
Bitmap bitmap1 = weakReference.get();
Log.e("Reference", "WeakReference---->" + bitmap1);
if (phantomReference == null) {
ReferenceQueue<Bitmap> queue = new ReferenceQueue<Bitmap>();
phantomReference = new PhantomReference<Bitmap>(readBitmapFromResource(getResources(), R.mipmap.bg_post_activity_5), queue);
}
Bitmap bitmap2 = phantomReference.get();
Log.e("Reference", "PhantomReference---->" + bitmap2);
}
public Bitmap readBitmapFromResource(Resources resources, int resourcesId) {
BitmapFactory.Options options = new BitmapFactory.Options();
return BitmapFactory.decodeResource(resources, resourcesId, options);
}
}
</code></pre>
第一次點擊打印信息:

通過打印信息可以虛引用直接回收掉了,或者可以說直接不存在引用。
接下來多次點擊打印信息:

在模擬內存使用越來越緊張的情況下,并沒有出現先回收弱引用,再回收軟引用,而是兩個一并回收掉了,其實按照Java正常引用順序是軟引用強于弱引用,但是從 Android 2.3 (API Level 9)開始,垃圾回收器會更傾向于回收持有軟引用或弱引用的對象,這讓軟引用像弱引用一樣變得不再可靠。所以圖片緩存不再使用軟引用而采用LRU算法。但是強引用一直毅力不倒。
總結:
從上面的介紹及測試對比可以得知,如果我們比較在意APP的性能的話,我們可以把哪些不常用并且占用內存比較大的對象用軟引用或者弱引用來做緩存處理,鑒于保險起見,可以酌情選擇使用弱引用還是軟引用,實測下來二者被回收的概率相差無幾。
來自:http://www.cnblogs.com/whoislcj/p/5895202.html