Android App 內(nèi)存泄漏檢查工具M(jìn)AT
Eclipse 有個(gè)插件工具M(jìn)AT(Memory Analyzer Tool)可以幫助定位內(nèi)存泄漏的對(duì)象。
- 安裝MAT Update site: http://archive.eclipse.org/mat/1.1/update-site/
 - 用DDMS工具Dump出問(wèn)題App的.hprof文件 比如com.world.test2.hprof Dump之前最好先運(yùn)行一下GC "Cause GC" , 確保dump出來(lái)的是還不能回收的對(duì)象等。
 - 用SDK tools下工具h(yuǎn)prof-conv.exe 做轉(zhuǎn)換 hprof-conv com.world.test2.hprof appleak.hprof
 - 用Eclipse “Open Head Dump”打開(kāi)新轉(zhuǎn)換的.hprof 文件--appleak.hprof 查看圖形化界面,一個(gè)一個(gè)檢查懷疑的點(diǎn)。
 
總結(jié): MAT tool不會(huì)直接告訴你哪里內(nèi)存泄漏,但是會(huì)列出懷疑的對(duì)象,需要你仔細(xì)檢查這些對(duì)象為什么沒(méi)有被釋放掉。
下面是測(cè)試code, 在Android 4.2.2上測(cè)試過(guò)。 1. 此種情況可以引起Activity無(wú)法回收的情況,因?yàn)橹苯佑妙?lèi)似private static Activity a0引用創(chuàng)建的Activity,導(dǎo)致Activity無(wú)法回收。 2. 此種情況沒(méi)有引起Activity 無(wú)法回收的情況。 按理說(shuō)這種情況應(yīng)該也會(huì)導(dǎo)致靜態(tài)Drawable 鎖定Activity, 引用關(guān)系mBackground1-->Button-->Activity. 待分析
- public class MainActivity extends Activity implements Button.OnClickListener{
 - final private static String TAG = "MainActivity";
 - private static Drawable mBackground1;
 - private static Drawable mBackground2;
 - private static Drawable mBackground3;
 - private static Drawable mBackground4;
 - private static Activity a0 ;
 - private static Activity a1 ;
 - private static Activity a2 ;
 - private static Activity a3 ;
 - private static Activity a4 ;
 - /*
 - * Shutdown intent
 - */
 - private final String INTENT_ACTION_REQUEST_SHUTDOWN =
 - "android.intent.action.ACTION_REQUEST_SHUTDOWN";
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - Log.v(TAG, "onCreate Activity="+this);
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.activity_main);
 - //1
 - if(false){
 - if(a0 == null){
 - a0 = this;
 - Log.v(TAG, "onCreate Activity a0="+a0);
 - }
 - else if(a1 == null){
 - a1 = this;
 - Log.v(TAG, "onCreate Activity a1="+a1);
 - }
 - else if(a2 == null){
 - a2 = this;
 - Log.v(TAG, "onCreate Activity a2="+a2);
 - }
 - else if(a3 == null){
 - a3 = this;
 - Log.v(TAG, "onCreate Activity a3="+a3);
 - }
 - else if(a4 == null){
 - a4 = this;
 - Log.v(TAG, "onCreate Activity a4="+a4);
 - }
 - }
 - //set up button listener
 - Button myButton = (Button)findViewById(R.id.button_poweroff);
 - myButton.setOnClickListener(this);
 - myButton = (Button)findViewById(R.id.button_reboot);
 - myButton.setOnClickListener(this);
 - //2
 - if (mBackground1 == null) {
 - Log.v(TAG, "onCreate mBackground1");
 - mBackground1 = getResources().getDrawable(R.drawable.adbroot_004);
 - myButton.setBackgroundDrawable(mBackground1);
 - }
 - else if(mBackground2 == null){
 - Log.v(TAG, "onCreate mBackground2");
 - mBackground2 = getResources().getDrawable(R.drawable.test002);
 - myButton.setBackgroundDrawable(mBackground2);
 - }
 - else if(mBackground3 == null){
 - Log.v(TAG, "onCreate mBackground3");
 - mBackground3 = getResources().getDrawable(R.drawable.test003);
 - myButton.setBackgroundDrawable(mBackground3);
 - }
 - else if(mBackground4 == null){
 - Log.v(TAG, "onCreate mBackground4");
 - mBackground4 = getResources().getDrawable(R.drawable.adbroot_003);
 - myButton.setBackgroundDrawable(mBackground4);
 - }
 - }
 















 
 
 









 
 
 
 