-
強引用(StrongReference)
- 強引用是開發(fā)過程中最常用的引用方式,當一個對象具有強引用時雷袋,操作系統(tǒng)進行 GC 回收處理是不會回收強引用的對象吉殃,即使系統(tǒng)內(nèi)存不足,Java虛擬機寧可拋OutOfMemoryError(內(nèi)存溢出錯誤)楷怒,寧可使程序異常終止蛋勺,也不會靠回收強引用的對象來解決內(nèi)存不足的問題。
- 只要把強引用對象 str 賦空值 null, 該對象就可以被 GC 垃圾回收器回收鸠删;因為該對象此時不再含有其他強引用抱完。
用法示例:
// 變量 str 表示強引用,指向 new String("junker") 這個對象
String str = new String("junker");
-
軟引用(SoftReference)
- 當JVM虛擬機內(nèi)存充足時刃泡,軟引用對象不會被 GC 垃圾回收器回收巧娱。
- 當JVM虛擬機內(nèi)存不足時,軟引用對象會被 GC 垃圾回收器回收捅僵。
- 未被回收的軟引用對象是一直會被程序占有的家卖。
用法示例:
MySoftObj softObj = new MySoftObj();
//軟引用實例
SoftReference softRef = new SoftReference(softObj);
//獲取軟引用保存的引用
MySoftObj anotherRef = (MySoftObj) softRef.get();
- 軟引用可以和引用隊列(ReferenceQueue)聯(lián)合使用來實現(xiàn)內(nèi)存緊張的高速緩存;如果軟引用引用的對象被回收庙楚,Java虛擬機會把改軟引用對象加到與之關(guān)聯(lián)的引用隊列中上荡。
用法示例:
MySoftObj softObj = new MySoftObj();
ReferenceQueue queue = new ReferenceQueue();
SoftReference softRef = new SoftReference(softObj, queue);
- 例如 對于處理圖片這種占用內(nèi)存大的邏輯,可以通過軟引用緩存起來馒闷。但是在實踐中酪捡,使用軟引用作為緩存時效率是比較低的,系統(tǒng)并不知道哪些軟引用指向的對象應該被回收纳账,哪些應該被保留逛薇。過早被回收的對象會導致不必要的工作,比如 Bitmap 要重新從 SdCard 或者 網(wǎng)絡上加載 到內(nèi)存疏虫。在Android開發(fā)中永罚,一種更好的選擇是使用 LruCache啤呼。
-
弱引用(WeakReference)
用法示例:
MyWeakObj weakObj = new MyWeakObj();
//弱引用實例
WeakReference weakReference = new WeakReference<>(weakObj);
//獲取弱引用保存的引用
MyWeakObj anotherRef = weakReference.get();
- 對于弱引用對象,當操作系統(tǒng)進行 GC 回收處理時呢袱,不管內(nèi)存空間是否足夠官扣,弱引用對象都會被回收。
- 如果一個對象除了具有弱引用還具有強引用羞福,GC回收時惕蹄,該對象是不會被回收的,操作系統(tǒng)只會回收只具有弱引用的對象治专。
- 弱引用常常被用于防止內(nèi)存泄漏卖陵,最常見的是單例和Handler造成的內(nèi)存泄漏。
- 對于軟引用場景舉個很常用的例子:
問題:
匿名內(nèi)部類異步處理耗時邏輯且持有外部Activity強引用张峰,當Activity被結(jié)束時泪蔫,可能會出現(xiàn)因耗時導致匿名內(nèi)部類在Activit結(jié)束后仍然未釋放Activity對象,至Activity對象不能夠被gc回收挟炬,進而引發(fā)內(nèi)存泄漏問題鸥滨。
解決方案:
可以把 匿名內(nèi)部類 寫成一個靜態(tài)類 比如叫 staticCallback,staticCallback 持有外部類的 弱引用谤祖。
回調(diào)的時候判斷下外部類還在不在婿滓,如果在就通知外部類更新,外部類不在就不用管粥喜。關(guān)鍵就是 callback 持有外部類的弱引用凸主。匿名內(nèi)部類都會隱式持有外部類的強引用,所以要把 callback 搞成一個靜態(tài)類额湘。
相關(guān)代碼實現(xiàn):
/**
* 將匿名內(nèi)部類對象卿吐,定義成全局變量,
* 這樣 baseCallBack 的生命周期就和 外部Activity 一樣
*/
protected BaseCallBack baseCallBack;
private void startLongTimeRequest() {
baseCallBack = new BaseCallBack() {
@Override
public void onSuccess(String data) {
//執(zhí)行業(yè)務邏輯
}
};
//執(zhí)行異步耗時請求
CustomManager.getInstance().requestApi(new BaseCallBackWeak(baseCallBack));
}
static class BaseCallBackWeak implements BaseCallBack {
private WeakReference<BaseCallBack> backWeakReference;
public BaseCallBackWeak(BaseCallBack callback) {
this.backWeakReference = new WeakReference<>(callback);
}
@Override
public void onSuccess(String data) {
//判斷弱引用對象是否被回收
if (backWeakReference != null && backWeakReference.get() != null) {
backWeakReference.get().onSuccess(data);
}
}
}
-
虛引用(PhantomReference)
1锋华、虛引用不能保證其保存對象生命周期嗡官,若保存對象只有虛引用,則其有效期完全隨機于GC的回收毯焕,在任何一個不確定的時間內(nèi)衍腥,都可能會被回收;而虛引用與其他幾者的引用不同在于纳猫,在使用PhantomReference婆咸,必須要和Reference聯(lián)合使用。
用法示例:
MyPhantomObj phantomObj = new MyPhantomObj();
//引用隊列
ReferenceQueue queue = new ReferenceQueue<>();
//虛引用
PhantomReference phantomReference = new PhantomReference(phantomObj, queue);
//獲取虛引用保存的引用
MyPhantomObj anotherRef = phantomReference .get();