1. 程式人生 > >單例模式引起的記憶體洩漏

單例模式引起的記憶體洩漏

單例模式是我們專案中經常使用的一個設計模式,但是如果使用不當,也會引發記憶體洩漏。

例如: 下面這種常見的寫法,傳了一個Context 進去

import android.content.Context;

public class Utils {
    private Context mContext;
    private static Utils utils;

    private Utils(Context mContext) {
        this.mContext = mContext;
    }

    public static Utils getInstance(Context mContext) {
        if (utils == null) {
            synchronized (Utils.class) {
                if (utils == null) {
                    utils = new Utils(mContext);
                }
            }
        }
        return utils;
    }
}

當我們使用的時候:

public class MainActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Utils.getInstance(this);
    }
}

我們先執行一下,並通過 Android studio 自帶的記憶體檢測工具測試一下當前的記憶體使用情況

注意:android studio  3.0 的記憶體測試工具 是 Profiler  ,android studio 3.0 之前使用的是 anroid  Monitor 

這裡我的android studio 的版本是3.0以上的

先看一下第一次執行時的記憶體佔用情況

然後旋轉一次螢幕之後

 

可以看到,記憶體使用大小有所上升。在多旋轉幾次

可以看到有明顯的上升。

我們點選 一個向下的箭頭按鈕,檢視分析日誌

可以看到,當前存在多個 MainActivity 的例項。

然後我們手動 gc(箭頭左邊的 垃圾桶按鈕),正常情況下,只會存在一個 MainActivity 例項,但是,我們多次gc後返現,仍然存在兩個MainActivity 的例項,如圖:

這就說明,已經產生了記憶體洩漏,GC 已經不能掌控這部分記憶體了。

 

原因:

首先,我們的單例模式使用的是 static 修飾的,我們知道,static 修飾的物件會一直存在記憶體中

 我們在 MainActivity  的onCreat() 方法中 ,呼叫了  Utils.getInstance(this)。把ManActicity 傳了進入,建立了 Utils 的例項。

當我們旋轉螢幕的時候,MainActivity  會走 onDestory() 方法,但是 當前MainAcivity 被 Utils物件 持有引用,

並不會被銷燬,然後 再次走onCreate()  方法,方法中 再次呼叫 Utils.getInstance(this),會把 新的MainActivity 物件傳進去

但是:  當前 的Utils 例項並不為null ,條件判斷走不進去,會直接返回 utils。

    public static Utils getInstance(Context mContext) {
        if (utils == null) {
            synchronized (Utils.class) {
                if (utils == null) {
                    utils = new Utils(mContext);
                }
            }
        }
        return utils;
    }

所以產生記憶體洩漏。

解決:

只需要把當前類的上下文,改為application就行

 

 

 

 

此時 我們旋轉螢幕,MainActivity 重寫載入。