單例模式引起的記憶體洩漏
單例模式是我們專案中經常使用的一個設計模式,但是如果使用不當,也會引發記憶體洩漏。
例如: 下面這種常見的寫法,傳了一個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 重寫載入。