歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

在Android 項目時的防止Memory leak 要注意的事項

一般來說,Java VM是會有Gargage Collect的。但是如果object在其他的object 有reference的話,那VM是不會做cleanup的。

常見的例子是在Activity 上發生。

因為在a) 由一個activity 跳到另一個activity 或是b)在screen rotation 時,Android 系統會新建一個新的Activity,而原先的Activity 會被釋放,最後會被Gargage Collect.。但如果其他的Class 有用上這個Activity ,這個activity 就不會被Gargage Collect,因而引起memory leak 的問題。

例子

public class MyActivity extends Activity{

 

public void onCreate(Bundle icicle){

     super.onCreate(icicle);

     Utility.registerCallback(this);

    

}

 

}

 

public class Utility

{

private static Classback m_callback = new Callback();

 

public static void registerCallback(Context c){

     m_callback.registerCallback(c);

}

}

 

public class Callback {

private context m_context;

 

public void registerCallback(Context c){

     m_context=c;

}

 

public void unregisterCallback(Context c){

    if ( c == m_context ){

        m_context=null;

}

}

 

}

在以上的例子中,因為class Callback 中的m_context 把 MyActivity 抓著了。 所以在這個Activity完成後,Garage Collect是不可以釋放MyActivity 的。

一個解決方案是在Activity離開前,釋放在外面的reference。  

例子

public class MyActivity extends Activity{

 

public void onCreate(Bundle icicle){

     super.onCreate(icicle);

     Utility.registerCallback(this);

    

}

 

public void onDestroy()

{

    super.onDestroy();

    Utility.unregisterCallback(this);

}

 

}

 

public class Utility

{

private static Classback m_callback = new Callback();

 

public static void registerCallback(Context c){

     m_callback.registerCallback(c);

}

public static void unregisterCallback(Context c){

     m_callback.unregisterCallback(c);

}

 

}

 

public class Callback {

private context m_context;

 

public void registerCallback(Context c){

     m_context=c;

}

 

public void unregisterCallback(Context c){

    if ( c == m_context ){

        m_context=null;

}

}

}

其他的相關事項

1)在SDK中的DigitalClock Widget ,因為DigitalClock要注冊一個observer,所以會用把載上DigitalClock widget的Activity作為那個observer。但在SDK的DigitalClock是有一個Bug的,因為在DigitalClock 的onDetachedFromWindow中是沒有unregister 那個observer的。 解決方法是自己寫一個DigitalClock。詳情請看附上的代碼(DigitalClockNew.java)。

2)在SDK中的Toast的function makeText 是要求傳一個Context的,但在Toast的代碼中,這個Context是會用做callback上。如果是傳Activity作為那個Context的話,那會發生memory leak的問題。解決方法是傳 Application Context,而不是ActivityContext。

如何查看Memory leak的問題

如果懷疑有memory leak的問題,可先執行那個apk在emulator上,然後在PC上執行adb shell,,然後執行ps,查看你的process 的pid。

在apk上執行有memory leak可疑的動作後,可以做下面的診斷

1.       執行 dumpsys meminfo <pid>

這個指令顯示pid的memory資料。注意是 Activity的 數量,如果數量是不斷上升,那就是有memory leak。 注意,因為在未執行Gargage Collect前,Activity是不會被釋放的。可以在DDMS上執行手動的Gargage Collect。

2.       把process 的memory dump 出來,看memory leak的所在

先執行 chmod 777 /data/misc,然後執行 kill -10 <pid> ,在 /data/misc 上會看到那個pid 的memory leak,(如heap-dump-tm1265266619-pid1673.hprof )

adb pull ( 如adb pull /data/misc/ heap-dump-tm1265266619-pid1673.hprof 1673.hprof )把這個檔案拷回電腦上。

然後,用在PC上執行hprof-conv (如hprof-conv  1673.hprof  1673_a.hprof) 把那個拷回來的hprof轉換成 Eclipse Memory Tool 可以支持的格式。

用Eclipse Memory Tool (http://www.eclipse.org/mat/), 打開轉換了的memory dump。 在Eclipse Memory Tool 上,按OQL,輸入 “select * from instanceof android.app.Activity” , 這個指令可以找所以在系統上是android.app.Activity 的 instance。(詳見下圖)

如果在object的旁帶有“Unknown”的話,那object是可以被Gargage Collect的。要看其他的object是什麼原因不可以被Gargage Collect 的話,可以在那個object上right-click,然後選Path to GC Roots, exclude weak/soft reference 。 (weak 和soft reference 都是可以被VM查到的,所以是可以Gargage Collect的。)

在Path to GC Roots 中,可以看到WidgetManagerHome 是因為Toast中的inner class TN 把 這個WidgetManagerHome抓住了。

Copyright © Linux教程網 All Rights Reserved