前言:
在開發(fā)項(xiàng)目的過程中 或多或少都有些地方不注意造成內(nèi)存泄漏導(dǎo)致App卡頓的情況發(fā)生 Android Studio也為我們提供了一些查找內(nèi)存泄漏的組件 今天就先學(xué)習(xí)下 如何使用Android Monitor來分析和查找項(xiàng)目中內(nèi)存泄漏的地方
案例:
public class CommUtil {
private static CommUtil instance;
private Context context;
private CommUtil(Context context) {
this.context=context;
}
public static CommUtil getInstance(Context context){
if(null==instance){
instance=new CommUtil(context);
}
return instance;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CommUtil instance = CommUtil.getInstance(this);
}
}
將Activity的實(shí)例被一個(gè)單例對(duì)象所持有弛作,相信這樣的代碼錯(cuò)誤大家應(yīng)該不會(huì)去犯糙俗,這里主要學(xué)習(xí)如何使用Android Monitor 就遷就一下,然后我們運(yùn)行起來 儿普,再將手機(jī)屏幕旋轉(zhuǎn)幾下(旋轉(zhuǎn)屏幕的時(shí)候 Activity會(huì)被銷毀重新創(chuàng)建安吁,但是這里的單例會(huì)持有銷毀Activity的實(shí)例就造成內(nèi)存泄漏)。
-
先看看Android Studio 的Android Monitor都有哪些功能 先只關(guān)注Memory這塊
Initiate Gc:點(diǎn)擊主動(dòng)去回收垃圾內(nèi)存
Dump java Heap: 點(diǎn)擊就會(huì)生成app運(yùn)行內(nèi)存快照.hprof文件
Free :代表還剩下的內(nèi)存
Allocated:代表已經(jīng)使用的內(nèi)存 -
Dump java Heap點(diǎn)擊就會(huì)生成app運(yùn)行內(nèi)存快照.hprof文件
-
通過內(nèi)存快照 看到MainActivity 在內(nèi)存中有3個(gè)實(shí)例 點(diǎn)擊進(jìn)行進(jìn)一步查看
Depth:對(duì)象被引用的深度
Shallow Size:對(duì)象實(shí)例的大小
Dominating Size:對(duì)象管轄范圍的內(nèi)存大小 -
在Instance區(qū)域我們看到了MainActivity的3個(gè)實(shí)例對(duì)象 已經(jīng)各個(gè)對(duì)象的引用深度和大小等 這里就明顯看到了MainActivtiy內(nèi)存泄漏了 這里說明一下 (在運(yùn)行項(xiàng)目的時(shí)候 手機(jī)屏幕旋轉(zhuǎn)了3下 所以生成了3個(gè)MianActivity實(shí)例 但是第二個(gè)MainActivity已經(jīng)被回收 因?yàn)楫?dāng)GC回收的時(shí)候會(huì)將除了第0個(gè)和最后這一個(gè)留著其他的都會(huì)被回收 所以當(dāng)你把手機(jī)屏幕旋轉(zhuǎn)3次以上的時(shí)候 內(nèi)存里面只會(huì)有2個(gè)Activity實(shí)例)
點(diǎn)擊編號(hào)2的MianActivity進(jìn)行查看:
Depth:對(duì)象被引用的深度
Shallow Size:對(duì)象實(shí)例的大小
Dominating Size:對(duì)象管轄范圍的內(nèi)存大小 -
根據(jù)上面的內(nèi)存對(duì)象引用樹就能得出結(jié)論分析(除CommUtil以外的地方是系統(tǒng)級(jí)的引用這里暫時(shí)先不用管) :
- CommUtil引用了MainActivity的context
- 引用深度Depth為1 對(duì)象大小為12 該對(duì)象管轄范圍大小為60781
然后改代碼:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CommUtil instance = CommUtil.getInstance(getApplicationContext());
}
}
-
該代碼運(yùn)行 且旋轉(zhuǎn)屏幕后 再生成內(nèi)存快照.hprof文件查看:
將this改為getApplicationContext()后 MainActivity在幾次旋轉(zhuǎn)屏幕后始終保持一個(gè)實(shí)例
總結(jié):
- 以上是通過已知案例來進(jìn)行對(duì)Android Monitor的簡單學(xué)習(xí) 在實(shí)際開發(fā)過程中還需要去仔細(xì)的分析(這個(gè)相對(duì)來講較困難 需要根據(jù)自己的一些經(jīng)驗(yàn)來看)
最后:
- 其實(shí)還有一個(gè)工具叫MAT Memory Analyzer 如何使用在下篇文章進(jìn)行講解