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

來源:互聯網
上載者:User

一般來說,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抓住了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.