Android中的WeakReference 弱引用


WeakReference 弱引用

定義:弱引用,與強引用(我們常見的引用方式)相對;特點是:GC在回收時會忽略掉弱引用對象(忽略掉這種引用關系),即:就算弱引用指向了某個對象,但只要該對象沒有被強引用指向,該對象也會被GC檢查時回收掉。

強引用實例自然不會被GC回收!

如何引出弱引用?弱引用的實際用途是什么?

什么是內存泄漏?Java使用有向圖機制,通過GC自動檢查內存中的對象;如果GC發現一個或一組對象為不可達的狀態,則將該對象從內存中回收。也就是說:一個對象不被任何引用所指向,則該對象會在被GC發現的時候回收。

可能導致內存泄漏的實例:

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mImageView.setImageBitmap(mBitmap);
        };
    };

當使用內部類(或者匿名類)來創建Handler的時候,Handler對象會隱式地持有一個外部類的對象(通常是Activity)的引用(否則怎么可能通過Handler來操作Activity的View?)。而Handler通常會伴隨着一個耗時的后台線程(比如:拉取網絡圖片);該后台線程在任務執行完畢后,通過消息機制通知Handler,然后Handler把圖片更新到界面上。假設用戶在網絡請求過程中關閉了Activity,正常情況下這個Activity不再被使用,就有可能被GC回收;但此時線程尚未執行完畢,而該線程持有Handler的引用(不然怎么發送消息給Handler?),Handler又持有Activity的引用,就導致該Activity無法被回收(內存泄漏),直到網絡請求結束(如:圖片下載完畢)。另外如果執行了Handler的postDelayed(),該方法會將Handler裝入一個Message,並把該Message推到MessageQueue中,由此產生了一條鏈式結構:MessageQueue->Message->Handler->Activity,導致Activity被持有引用而無法被回收。(總結:實例對象被其他對象持有引用,而無法被回收)

內存泄漏的危害是什么?內存泄漏會引發虛擬機占用內存過高。對於Android應用程序來說,用戶打開一個Activity,使用完之后關閉,內存泄漏;執行上述步驟多次,程序占用內存超過系統限制。

如何避免內存泄漏?可以使用什么方法?由此引出了弱引用。

用於非必需對象,被弱引用關聯的對象只能生存到下一次GC發生之前。當GC工作時,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象。

/**
 * <功能描述> 用於加載Bitmap實例
 * 
 * @author Administrator
 */
public class AsyncDrawable extends BitmapDrawable {
    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
    public AsyncDrawable(Resources res, Bitmap bitmap,
            BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        // bitmapWorkerTaskReference實例關聯BitmapWorkerTask
        bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(
                bitmapWorkerTask);
    }
    public BitmapWorkerTask getBitmapWorkerTask() {
        return bitmapWorkerTaskReference.get();
    }
}

此時 WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference 關聯了 bitmapWorkerTask 實例(可認為兩者是“好朋友”關系);在虛擬機看來 bitmapWorkerTask 實例是垃圾時,但 WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference 不是垃圾。但垃圾並不會立即被回收,也就是仍然可以使用對象 bitmapWorkerTask 實例;若該對象已被清理,則必須重新構建對象,並再一次關聯。

好處在於:可以申請任意多個 bitmapWorkerTask 實例對象,並與弱引用對象關聯;使用前,先判斷是否已被釋放;如果已被釋放,則重新申請;若未被釋放,則直接使用。WeakReference負責了釋放規則。

使用了上述代碼后,用戶在關閉Activity之后,就算后台線程還沒有結束,但由於僅有一個來自Handler的弱引用指向Activity,所有GC仍然會在檢查的時候把Activity回收掉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM