天天看點

【Android】了解強引用、軟引用、弱引用、虛引用

【Android】了解強引用、軟引用、弱引用、虛引用

強引用(StrongReference)

強引用是開發過程中最常用的引用方式,當一個對象具有強引用時,作業系統進行 ​

​GC​

​​ 回收處理是​

​不會回收強引用的對象​

​,即使系統記憶體不足,

Java虛拟機甯可抛 ​

​OutOfMemoryError(記憶體溢出錯誤)​

​,甯可使程式異常終止,也不會靠回收強引用的對象來解決記憶體不足的問題。

隻要把強引用對象 str 賦空值 null, 該對象就可以被 GC 垃圾回收器回收;因為該對象此時不再含有其他強引用。

// 變量 str 表示強引用,指向 new String("codingce") 這個對象
String str = new String("codingce");      

軟引用(SoftReference)

當JVM虛拟機記憶體充足時,軟引用對象不會被 GC 垃圾回收器回收。

當JVM虛拟機記憶體不足時,軟引用對象會被 GC 垃圾回收器回收。

未被回收的軟引用對象是一直會被程式占有的。

示例

MySoftObj softObj = new MySoftObj();
 //軟引用執行個體
 SoftReference softRef = new SoftReference(softObj);
 //擷取軟引用儲存的引用
 MySoftObj anotherRef = (MySoftObj) softRef.get();      

軟引用可以和引用隊列(ReferenceQueue)聯合使用來實作記憶體緊張的高速緩存;如果軟引用引用的對象被回收,Java虛拟機會把改軟引用對象加到與之關聯的引用隊列中。

MySoftObj softObj = new MySoftObj();
 ReferenceQueue queue = new  ReferenceQueue();
 SoftReference  softRef = new  SoftReference(softObj, queue);      

例如: 對于處理圖檔這種占用記憶體大的邏輯,可以通過軟引用緩存起來。但是在實踐中,使用軟引用作為緩存時效率是比較低的,系統并不知道哪些軟引用指向的對象應該被回收,哪些應該被保留。過早被回收的對象會導緻不必要的工作,比如 Bitmap 要重新從 SdCard 或者 網絡上加載 到記憶體。在Android開發中,一種更好的選擇是使用 ​

​LruCache​

​。

弱引用(WeakReference)

MyWeakObj weakObj = new MyWeakObj();
//弱引用執行個體 
WeakReference weakReference = new WeakReference<>(weakObj); 
//擷取弱引用儲存的引用 
MyWeakObj anotherRef = weakReference.get();      

對于弱引用對象,當作業系統進行 GC 回收處理時,不管記憶體空間是否足夠,弱引用對象都會被回收。

如果一個對象除了具有弱引用還具有強引用,GC回收時,該對象是不會被回收的,作業系統隻會回收隻具有弱引用的對象。

弱引用常常被用于防止記憶體洩漏,最常見的是單例和Handler造成的記憶體洩漏。

對于軟引用場景舉個很常用的例子:

問題:

匿名内部類異步處理耗時邏輯且持有外部Activity強引用,當Activity被結束時,可能會出現因耗時導緻匿名内部類在Activit結束後仍然未釋放Activity對象,至Activity對象不能夠被gc回收,進而引發記憶體洩漏問題。

解決方案:

可以把 匿名内部類 寫成一個靜态類 比如叫 staticCallback,staticCallback 持有外部類的 弱引用。

回調的時候判斷下外部類還在不在,如果在就通知外部類更新,外部類不在就不用管。關鍵就是 callback 持有外部類的弱引用。匿名内部類都會隐式持有外部類的強引用,是以要把 callback 搞成一個靜态類。

代碼

/**
     * 将匿名内部類對象,定義成全局變量,
     * 這樣 baseCallBack 的生命周期就和 外部Activity 一樣
     */
    protected BaseCallBack baseCallBack;

    private void startLongTimeRequest() {
        baseCallBack = new BaseCallBack() {
            @Override
            public void onSuccess(String data) {
                //執行業務邏輯
            }
        };
        //執行異步耗時請求
        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);
            }
        }
    }      

對弱引用的注意事項(​

​目前的了解就是,最好的還是自行管理好對象的生命周期​

​)

​Memory leaks cannot be fixed by replacing strong references with weak references. It’s a common solution when attempting to quickly address memory issues, however it never works. The bugs that were causing references to be kept longer than necessary are still there. On top of that, it creates more bugs as some objects will now be garbage collected sooner than they should. It also makes the code much harder to maintain.​

虛引用(PhantomReference)

MyPhantomObj phantomObj = new MyPhantomObj();
//引用隊列 
ReferenceQueue queue = new ReferenceQueue<>(); 
//虛引用 
PhantomReference phantomReference = new PhantomReference(phantomObj, queue); 
//擷取虛引用儲存的引用 
MyPhantomObj anotherRef = phantomReference .get();