亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android開發中應該避免的內存泄露

發布時間:2020-07-21 23:34:09 來源:網絡 閱讀:591 作者:百度MTC 欄目:移動開發


一、背景和目的:

目前許多開發人員在Android開發過程中,較少關注實現細節和內存使用,容易會造成內存泄露,導致程序OOM

本文會通過代碼向大家介紹在Android開發過程中常見的內存泄露。

二、常見的內存泄露代碼

1、使用Handler造成的內存問題

Android開發過程中,Handler是比較常用的,通過Handler發送Message與主線程進行通信,Message發送之后是存儲在MessageQueue中的,有些Message并不是馬上被處理的,在Message中存在一個Target,是Handler的一個引用,如果MessageHandler中的存在時間過長,會導致Handler無法被回收。如果Handler非靜態,則會導致相關引用的Activity或者Service不會回收,所以在處理Hanlder之類的內部類的時候,應該要將Handler定義為靜態內部類,同樣在使用HandlerThread的時候也需要注意,我們來看看代碼:

Android開發中應該避免的內存泄露

這個代碼存在泄漏問題,因為HandlerThread內部會不斷的循環執行,它不會自己結束,線程的生命周期超過了activity生命周期,當橫豎屏切換,HandlerThread線程的數量會隨著activity重建次數的增加而增加。

我們應該在onDestroy時將線程停止掉:mThread.getLooper().quit();

另外,對于不是HandlerThread的線程,也應該確保activity消耗后,線程已經終止,可以這樣做:在onDestroy時調用mThread.join();

2、使用非靜態內部類的靜態實例

Android開發中應該避免的內存泄露

  上面的代碼中的sInstance實例類型為靜態實例,在第一個MainActivityact實例創建時,sInstance會獲得并一直持有activity的引用。當MainAcitivity銷毀后重建,因為sInstance持有activity的引用,所以activity是無法被GC回收的,進程中會存在2MainActivity實例(activity和重建后的MainActivity實例),這個activity對象就是一個無用的但一直占用內存的對象,即無法回收的垃圾對象。所以,對于lauchMode不是singleInstanceActivity,應該避免在activity里面實例化其非靜態內部類的靜態實例。

3、在Activity中使用靜態成員

Android開發中應該避免的內存泄露

  由于用靜態成員sBackground 緩存了drawable對象,所以activity加載速度會加快,但是這樣做是錯誤的。因為它會導致activity銷毀后無法被系統回收。label.setBackgroundDrawable函數調用會將label賦值給sBackground的成員變量。上面代碼意味著:sBackgroundGC Root)會持有TextView對象,而TextView持有Activiy對象。所以導致Activity對象無法被系統回收。

  以上2個例子的內存泄漏都是因為Activity的引用的生命周期超越了activity對象的生命周期。也就是常說的Context泄漏,想要避免context相關的內存泄漏,需要注意以下幾點:

l  不要對activitycontext長期引用(activity的引用的生存周期應該和activity的生命周期相同)

l  在可以使用applicationcontext的情況下,盡可能使用applicationcontext來替代和activity相關的context

l  如果一個acitivity的非靜態內部類的生命周期不受控制,那么我們就應該避免這樣使用。

4、注冊某個對象后未注銷

注冊廣播接收器、注冊觀察者等等,比如: 在調用registerReceiver后,若未調用unregisterReceiver,它會導致BroadcastReceiver不會被unregister而導致內存泄露,我們經常會看到類似下面的代碼:

Android開發中應該避免的內存泄露

5、集合中對象沒清理造成的內存泄露

我們通常把一些對象的引用加入到了集合中,當我們不需要該對象時,如果沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,如果對象不斷增大,達到一定的值的時候程序就會OOM

 

6、資源對象沒關閉造成的內存泄露

資源性對象比如(CursorFile文件等)往往都用了一些緩沖,我們在不使用的時候,應該及時關閉它們,以便它們的緩沖及時回收內存。它們的緩沖不僅存在于Java虛擬機內,還存在于Java虛擬機外。如果我們僅僅是把它的引用設置為null,而不關閉它們,往往會造成內存泄露。因為有些資源性對象,比如SQLiteCursor(在析構函數finalize(),如果我們沒有關閉它,它自己會調close()關閉),如果我們沒有關閉它,系統在回收它時也會關閉它,但是這樣的效率太低了。因此對于資源性對象在不使用的時候,應該立即調用它的close()函數,將其關閉掉,然后再置為null.在我們的程序退出時一定要確保我們的資源性對象已經關閉。

 

程序中經常會進行查詢數據庫的操作,但是經常會有使用完畢Cursor后沒有關閉的情況。如果我們的查詢結果集比較小,對內存的消耗不容易被發現,只有在長時間大量操作的情況下才會復現內存問題,這樣就會給以后的測試和問題排查帶來困難和風險。

寫代碼時,經常會有人忘記調用close, 或者因為代碼邏輯問題狀況導致close未被調用。

錯誤的代碼:

Android開發中應該避免的內存泄露

修正后的代碼:

Android開發中應該避免的內存泄露

7、一些不良代碼成內存壓力

有些代碼并不造成內存泄露,但是它們或是對沒使用的內存沒進行有效及時的釋放,或是沒有有效的利用已有的對象而是頻繁的申請新內存,對內存的回收和分配造成很大影響的,容易迫使虛擬機不得不給該應用進程分配更多的內存,增加vm的負擔,造成不必要的內存開支。

7.1   Bitmap使用不當

一、需要及時的銷毀。

雖然,系統能夠確認Bitmap分配的內存最終會被銷毀,但是由于它占用的內存過多,所以很可能會超過Java堆的限制。因此,在用完Bitmap時,要及時的recycle掉。recycle并不能確定立即就會將Bitmap釋放掉,但是會給虛擬機一個暗示:“該圖片可以釋放了”。

二、需要設置一定的采樣率。

   有時候,我們要顯示的區域很小,沒有必要將整個圖片都加載出來,而只需要記載一個縮小過的圖片,這時候可以設置一定的采樣率,那么就可以大大減小占用的內存。如下面的代碼:

Android開發中應該避免的內存泄露

三、巧妙的運用軟引用(SoftRefrence

有些時候,我們使用Bitmap后沒有保留對它的引用,因此就無法調用Recycle函數。這時候巧妙的運用軟引用,可以使Bitmap在內存不足時得到有效的釋放。如下:

Android開發中應該避免的內存泄露

7.2使用Adapter時,沒有使用緩存的 ConvertView

  以構造ListViewBaseAdapter為例,在BaseAdapter中提共了方法:

  來向ListView提供每一個item所需要的view對象。初始時ListView會從BaseAdapter中根據當前的屏幕布局實例化一定數量的view對象,同時ListView會將這些view對象緩存起來。當向上滾動ListView時,原先位于最上面的list itemview對象會被回收,然后被用來構造新出現的最下面的list item。這個構造過程就是由getView()方法完成的,getView()的第二個形參 View convertView就是被緩存起來的list itemview對象(初始化時緩存中沒有view對象則convertViewnull)

  由此可以看出,如果我們不去使用convertView,而是每次都在getView()中重新實例化一個View對象的話,即浪費時間,也造成內存垃圾,給垃圾回收增加壓力,如果垃圾回收來不及的話,虛擬機將不得不給該應用進程分配更多的內存,造成不必要的內存開支。ListView回收list itemview對象的過程可以查看:

android.widget.AbsListView.JavaAndroid開發中應該避免的內存泄露

Android開發中應該避免的內存泄露

 

         錯誤的代碼:

Android開發中應該避免的內存泄露


  修正示例代碼:

 

Android開發中應該避免的內存泄露

7.3適當的使用對象池

不要在經常調用的方法中創建對象,每次new之后都丟棄,尤其是忌諱在循環中創建對象。在android support v4包中包含Pools類,其實就是對象池,使用方法也比較簡單,具體可以參考下面的MyPools這個類。

Android開發中應該避免的內存泄露

百度MTC是業界領先的移動應用測試服務平臺,為廣大開發者在移動應用測試中面臨的成本、技術和效率問題提供解決方案。同時分享行業領先的百度技術,作者來自百度員工和業界領袖等。

>>如有問題,歡迎與我溝通

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

井研县| 涪陵区| 祁连县| 长乐市| 建平县| 嘉峪关市| 大渡口区| 张家口市| 巴南区| 故城县| 繁昌县| 云林县| 当阳市| 开平市| 唐山市| 富平县| 宣化县| 阳山县| 北海市| 永安市| 江门市| 石嘴山市| 海晏县| 商丘市| 宁海县| 兴隆县| 靖边县| 临潭县| 吉木乃县| 绍兴县| 临海市| 友谊县| 资溪县| 颍上县| 达孜县| 姚安县| 即墨市| 休宁县| 榆中县| 丽江市| 巴彦淖尔市|