前言:本篇文章如題,講解關(guān)于性能優(yōu)化中央串,使用單例模式所引起的內(nèi)存泄露得原因及解決方法在Android Studio中通過報表查看引用樹谎替,下面開始正題;**
什么是內(nèi)存泄露:
簡單的說:當(dāng)一個對象已經(jīng)不被使用蹋辅,本應(yīng)當(dāng)別回收,但被另一個正在使用的對象所吃用挫掏,導(dǎo)致該對象無法被回收侦另;
更多的關(guān)于內(nèi)存泄露的描述請超看相關(guān)文章https://yq.aliyun.com/articles/3009
單例模式的隱患
下面是一段單例代碼:
private static CommUtils instance;
private Context context;
public CommUtils(Context context) {
this.context = context;
}
public static CommUtils getInstance(Context context){
if (instance == null){
instance = new CommUtils(context);
}
return instance;
}
}```
****
>**該類在MainActivity中的使用如下代碼:**
```public class PerformsActivity{
@override
protected void onCreate(Bundle saveInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_performs);
CommUtils commUtils = CommUtils.getInstance(this);
}
}```
####上面的這段代碼是我們在寫單例的時候經(jīng)常寫的,但是在這個單例的使用是存在內(nèi)存泄露風(fēng)險的;
>原因是:當(dāng)手機進行橫豎屏切換的時候或者Activity過多內(nèi)存使用緊張的時候褒傅,系統(tǒng)銷毀Activity弃锐,但在這個時候該Activity被CommUtils工具類所持有,導(dǎo)致Activity無法被系統(tǒng)回收從而導(dǎo)致內(nèi)存泄露
####我們通過Android Studio的Android Monitor工具來查看Activity的回收情況###
![啟動進入Activity內(nèi)存使用情況.png](http://upload-images.jianshu.io/upload_images/2056505-721687f814e1a158.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>通過Android Monitor使用了的內(nèi)存為:17.09MB 空閑2.61MB
####此時進行橫豎屏切換
![切換后的內(nèi)存使用情況.png](http://upload-images.jianshu.io/upload_images/2056505-e5530d2073dc0258.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>此時使用的內(nèi)存為:18.16MB 空閑:2.36MB
**在Android Monitor的左上角有一個Dump Java Heap的按鈕殿托;該按鈕是快照按鈕對當(dāng)前應(yīng)用的對象狀態(tài)進行一次記錄霹菊;在點擊左側(cè)的Captures對快照進行查看和分析;**
![進行快照.png](http://upload-images.jianshu.io/upload_images/2056505-194e6d0dcae71e5c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####此時在橫豎屏切換前后進行兩次快照并對快照進行查看
![第一次快照進行超看.png](http://upload-images.jianshu.io/upload_images/2056505-9b1cd3cd41b74941.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![對第二次快照進行查看.png](http://upload-images.jianshu.io/upload_images/2056505-9a6bf5fd1fe6af6a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>在第一次快照中的Instance中我們看到PerformsActivity的實例有一個支竹;第二次快照中 Instance中PerformsActivity實例有兩個旋廷,點擊兩個實例可以查看到該實例的引用樹,該實例被CommUtils所持有從而導(dǎo)致內(nèi)存泄露礼搁;
####如何解決
>有兩種方式解決該單例所導(dǎo)致的內(nèi)存泄露饶碘;第一種方式是使用全局的Application上下文Context參數(shù)使用CommUtils,第二種方式使用弱引用的方式解決代碼如下:
####一.使用全局Application上下文:
```public class PerformsActivity{
@override
protected void onCreate(Bundle saveInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_performs);
CommUtils commUtils = CommUtils.getInstance(getApplicationContext());
}
}```
####二.使用靜態(tài)變量的弱引用
```public class CommUtils {
private static WeakReference<CommUtils> WeakReferenceInstance;
private Context context;
public CommUtils(Context context) {
this.context = context;
}
public static CommUtils getInstance(Context context){
if (WeakReferenceInstance == null || WeakReferenceInstance.get() == null) {
WeakReferenceInstance = new WeakReference<CommUtils>(new CommUtils(context));
}
return WeakReferenceInstance.get();
}
}```
**如發(fā)現(xiàn)錯誤,請指正B狻扎运!**