Android下常見的內存泄露 經典

因爲Android使用Java作爲開發語言,很多人在使用會不注意內存的問題。

於是有時遇到程序運行時不斷消耗內存,最終導致OutOfMemery,程序異常退出,這就是內存泄露導致的。

我們現在就來總結一下可能導致內存泄露的情況:

  1. 查詢數據庫而沒有關閉Cursor

    Android中,Cursor是很常用的一個對象,但在寫代碼是,經常會有人忘記調用close, 或者因爲代碼邏輯問題狀況導致close未被調用。


    通常,在Activity中,我們可以調用startManagingCursor或直接使用managedQuery讓Activity自動管理Cursor對象。
    但需要注意的是,當Activity介紹後,Cursor將不再可用!
    若操作Cursor的代碼和UI不同步(如後臺線程),那沒需要先判斷Activity是否已經結束,或者在調用OnDestroy前,先等待後臺線程結束。

    除此之外,以下也是比較常見的Cursor不會被關閉的情況:

    1. try {  
    2.     Cursor c = queryCursor();  
    3.     int a = c.getInt(1);  
    4.     ......  
    5.     c.close();  
    6. catch (Exception e) {  
    7. }  
    雖然表面看起來,Cursor.close()已經被調用,但若出現異常,將會跳過close(),從而導致內存泄露。

    所以,我們的代碼應該以如下的方式編寫:

    1. Cursor c = queryCursor();  
    2. try {      
    3.     int a = c.getInt(1);  
    4.     ......  
    5. catch (Exception e) {  
    6. finally {  
    7.     c.close(); //在finally中調用close(), 保證其一定會被調用   
    8. }  

  2. 調用registerReceiver後未調用unregisterReceiver().

    在調用registerReceiver後,若未調用unregisterReceiver,其所佔的內存是相當大的。
    而我們經常可以看到類似於如下的代碼:

    1. registerReceiver(new BroadcastReceiver() {  
    2.     ...  
    3. }, filter); ...  
    這是個很嚴重的錯誤,因爲它會導致BroadcastReceiver不會被unregister而導致內存泄露。


  3. 未關閉InputStream/OutputStream

    在使用文件或者訪問網絡資源時,使用了InputStream/OutputStream也會導致內存泄露


  4. Bitmap使用後未調用recycle()

    根據SDK的描述,調用recycle並不是必須的。但在實際使用時,Bitmap佔用的內存是很大的,所以當我們不再使用時,儘量調用recycle()以釋放資源。


  5. Context泄露

    這是一個很隱晦的內存泄露的情況。
    先讓我們看一下以下代碼:
    1. private static Drawable sBackground;  
    2.   
    3. @Override  
    4. protected void onCreate(Bundle state) {  
    5.   super.onCreate(state);  
    6.     
    7.   TextView label = new TextView(this);  
    8.   label.setText("Leaks are bad");  
    9.     
    10.   if (sBackground == null) {  
    11.     sBackground = getDrawable(R.drawable.large_bitmap);  
    12.   }  
    13.   label.setBackgroundDrawable(sBackground);  
    14.     
    15.   setContentView(label);  
    16. }  

    在這段代碼中,我們使用了一個static的Drawable對象。
    這通常發生在我們需要經常調用一個Drawable,而其加載又比較耗時,不希望每次加載Activity都去創建這個Drawable的情況。
    此時,使用static無疑是最快的代碼編寫方式,但是其也非常的糟糕。
    當一個Drawable被附加到View時,這個View會被設置爲這個Drawable的callback (通過調用Drawable.setCallback()實現)。
    這就意味着,這個Drawable擁有一個TextView的引用,而TextView又擁有一個Activity的引用。
    這就會導致Activity在銷燬後,內存不會被釋放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章