主頁 > 移動端開發 > 真是恍然大悟啊!Android之記憶體泄漏除錯學習與總結

真是恍然大悟啊!Android之記憶體泄漏除錯學習與總結

2021-06-15 07:22:22 移動端開發

大家有或經常碰到OOM的問題,對吧?很多這樣的問題只要一出現相信大家的想法跟我的一樣,就是自己的應用:優化、優化、再優化!而且如果出現類似于OOM這樣級別的問題,根本就不好處理,LogCat日志中顯示的資訊僅僅是OOM,并不會給你提示如何解決的方法或思路,因為引起OOM的原因是你應用的問題,不是系統問題!應該想下,在優化之前找到需要優化的地方,再去做優化操作不是更直接嗎?相信大多數朋友應該經常聽過或使用Jnuit除錯吧,好了,廢話不多說,今天就跟大家一起來學習總結下OOM的除錯方法,來找到需要優化的地方,要知道OOM也是可以一步步除錯的:

Android技術交流群653583088

首先,先一起來做些小小的知識鋪墊:

Android(Java)中常見的容易引起記憶體泄漏的不良代碼:

  1. 查詢資料庫沒有關閉游標
    程式中經常會進行查詢資料庫的操作,但是經常會有使用完畢Cursor后沒有關閉的情況,如果我們的查詢結果集比較小,對記憶體的消耗不容易被發現,只有在常時間大量操作的情況下才會復現記憶體問題,這樣就會給以后的測驗和問題排查帶來困難和風險示例代如下碼:
if (cursor.moveToNext()) { 
  ... ... 
} 
 修正示例代碼: 
Cursor cursor = null; 
try { 
  cursor = getContentResolver().query(uri ...); 
  if (cursor != null && cursor.moveToNext()) { 
  ... ... 
  } 
} finally { 
  if (cursor != null) { 
  try { 
  cursor.close(); 
  } catch (Exception e) { 
  //ignore this 
  } 
  } 
} 
  1. 構造Adapter時,沒有使用快取的 convertView
  2. Bitmap物件不在使用時呼叫recycle()沒有及時釋放
    如果一個Bitmap物件比較占記憶體,當它不在被使用的時候,可以呼叫Bitmap.recycle()方法回收此物件的像素所占用的記憶體
    4.沒有及時釋放物件的參考
    簡單舉個例子:比如兩個Activity之間傳遞的Context 或其它的自定義物件,使用完后必須立即釋放 即:Activity = null ; Context = null ; Object = null;可以的話在這釋放物件之后通知系統來回收:System.gc();這樣最好了!
    Android主要應用在嵌入式設備當中,而嵌入式設備由于一些眾所周知的條件限制,通常都不會有很高的配置,特別是記憶體是比較有限的,如果我們撰寫的代 碼當中有太多的對記憶體使用不當的地方,難免會使得我們的設備運行緩慢,甚至是死機,為了能夠使得Android應用程式安全且快速的運行,Android 的每個應用程式都會使用一個專有的Dalvik虛擬機實體來運行,它是由Zygote服務行程演變過來的,也就是說每個應用程式都是在屬于自己的行程中運行的(問題一:這個地方怎么知道是在屬于自己的行程中運行的?大家繼續,答案會在下面詳細介紹),一方面,如果程式在運行程序中出現了記憶體泄漏的問題,僅僅會使得自己的行程被殺掉,而不會影響其他行程(如果是system_process 等系統行程出問題的話,則會引起系統重啟),另一方面Android為不同型別的行程分配了不同的記憶體使用上限,如果應用行程使用的記憶體超過了這個上限, 則會被系統視為記憶體泄漏,從而被殺掉
    下面來解釋下問題一:”每個應用程式都是在屬于自己的行程中運行的”這句話,對于這句話,大家只記住一點:“當一個程式第一次啟動的時候,Android會啟動一個LINUX行程和一個主執行緒,默認的情況下,所有該程式的組件都將在該行程和執行緒中運行,”~_ O_O !!!**

同時,Android會為每個應用程式分配一個單獨的LINUX用戶,Android會盡量保留一個正在運行行程,只在記憶體資源出現不足時,Android會嘗試停止一些行程從而釋放足夠的資源給其他新的行程使用, 也能保證用戶正在訪問的當前行程有足夠的資源去及時地回應用戶的事件,Android會根據行程中運行的組件類別以及組件的狀態來判斷該行程的重要性,Android會首先停止那些不重要的行程,按照重要性從高到低一共有五個級別就是我們常說的:前臺行程、可見行程、服務行程、后臺行程、空行程(此處概念略,大家自己查)
還有個小擴展:當一個程式第一次啟動時,Android會同時啟動一個對應的主執行緒(Main Thread),主執行緒主要負責處理與UI相關的事件,如用戶的按鍵事件,用戶接觸螢屏的事件以及螢屏繪圖事件,并把相關的事件分發到對應的組件進行處理,所以主執行緒通常又被叫做UI執行緒,在開發Android應用時必須遵守單執行緒模型的原則: Android UI操作并不是執行緒安全的并且這些操作必須在UI執行緒中執行,Android的UI是單執行緒(Single-threaded)的,為了避免拖住GUI,一些較費時的物件應該交給獨立的執行緒去執行,如果幕后的執行緒來執行UI物件,Android就會發出錯誤訊息 CalledFromWrongThreadException,以后遇到這樣的例外拋出時就要知道怎么回事咯!**

** 好了,鋪墊知識就寫這么多了,下面直接進入主題了:OOM除錯**

方式一:使用記憶體監測工具 DDMS –> Heap:(真機、模擬器均可使用)

** 1. 啟動eclipse后,切換到DDMS透視圖,并確認Devices視圖、Heap視圖都是打開的,沒打開的直接Window>ShowView>自己選;**
** 2. 將手機通過USB鏈接至電腦,鏈接時需要確認手機是處于“USB除錯”模式**

** 3. 鏈接成功后,在DDMS的Devices視圖中將會顯示手機設備的序列號,以及設備中正在運行的部分行程資訊;**

** 4. 點擊選中想要監測的行程,如果在行程串列中未出現你的行程的話隨便選中一條讓Device一排的工具處于可用狀態,再點擊下Update Heap讓其自動找到我們跑的應用的行程,比如臨時跑的兩個應用行程如圖
111.png

** 5. 點擊Heap視圖中的“Cause GC”按鈕;**

222.png

** 6.點擊Cause GC之后就可以看到我們應用的記憶體情況如下圖:**

333.png

說明:
a) 點擊“Cause GC”按鈕相當于向虛擬機請求了一次gc操作;
b) 當記憶體使用資訊第一次顯示以后,無須再不斷的點擊“Cause GC”,Heap視圖界面會定時重繪,在對應用的不斷的操作程序中就可以看到記憶體使用的變化;
c) 記憶體使用資訊的各項引數根據名稱即可知道其意思,不知道具體意思的朋友自行用工具(有道、詞霸查去)

** 知道工具使用了,那么如何才能知道我們的程式是否有記憶體泄漏的可能性呢,這里需要注意一個值:Heap視圖中部有一個Type叫做data object,即資料物件,也就是我們的程式中大量存在的型別別的物件,在data object一行中有一列是“Total Size”,其值就是當前行程中所有Java資料物件的記憶體總量,如果大家想要看“Total Size”是分配的具體資訊可以點擊“data object這一行來查看詳細資訊,如下圖”(大家看不清楚的點擊看大圖)**

4.png

一般情況下,在data object行的“Total Size”這個值的大小決定了是否會有記憶體泄漏,可以這樣判斷:
a) 不斷的操作當前應用,同時注意觀察data object的Total Size值;
b) 正常情況下Total Size值都會穩定在一個有限的范圍內,也就是說由于程式中的的代碼良好,沒有造成物件不被垃圾回收的情況,所以說雖然我們不斷的操作會不斷的生成很多對 象,而在虛擬機不斷的進行GC的程序中,這些物件都被回收了,記憶體占用量會會落到一個穩定的水平;
c) 反之如果代碼中存在沒有釋放物件參考的情況,則data object的Total Size值在每次GC后不會有明顯的回落,隨著操作次數的增多Total Size的值會越來越大,
** 直到到達一個上限后導致行程被殺掉,**

** Android為應用行程分配的記憶體上限如下所示:(下面這些是網上查到的,不懂下面的語法,但知道有限制這么一回事就夠了,此處不研究下面的代碼)**

 killed by the kernel. These are used in ActivityManagerService
  setprop ro.FOREGROUND_APP_ADJ 0
  setprop ro.VISIBLE_APP_ADJ 1
  setprop ro.SECONDARY_SERVER_ADJ 2
  setprop ro.BACKUP_APP_ADJ 2
  setprop ro.HOME_APP_ADJ 4
  setprop ro.HIDDEN_APP_MIN_ADJ 7
  setprop ro.CONTENT_PROVIDER_ADJ 14
  setprop ro.EMPTY_APP_ADJ 15
 Define the memory thresholds at which the above process classes will
 be killed. These numbers are in pages (4k)
 setprop ro.FOREGROUND_APP_MEM 1536
 setprop ro.VISIBLE_APP_MEM 2048
  setprop ro.SECONDARY_SERVER_MEM 4096
  setprop ro.BACKUP_APP_MEM 4096
  setprop ro.HOME_APP_MEM 4096
 setprop ro.HIDDEN_APP_MEM 5120
  setprop ro.CONTENT_PROVIDER_MEM 5632
 setprop ro.EMPTY_APP_MEM 6144
 Write value must be consistent with the above properties.
 Note that the driver only supports 6 slots, so we have HOME_APP at the
same memory level as services.
write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
  write /proc/sys/vm/overcommit_memory 1
 write /proc/sys/vm/min_free_order_shift 4
 write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144
 Set init its forked children’s oom_adj
write /proc/1/oom_adj -16

方式二:

**記憶體監測工具 DDMS –> Heap **
**使用記憶體分析工具 MAT(Memory Analyzer Tool) **
(一) 生成.hprof檔案 (生成很簡單,直接點擊Device 工具列中的 Dump HPROF file即可生成)
**(二) 使用MAT匯入.hprof檔案 **
(三) 使用MAT的視圖工具分析記憶體

** 總之,使用DDMS的Heap視圖工具可以很方便的確認我們的程式是否存在記憶體泄漏的可能性,這個地方順帶著也簡單的說一下,如果大家想要跟蹤更詳細的記憶體是怎樣分配的話,可以學著使用下Windows>ShowView>Allocation Tracker工具來定位你的記憶體什么時候被什么東西占用了,是bundlea或HashMap或ArrayList焦點或是其它的什么占用了這些都可以在這個插件中查看到的,簡單的使用方法就是:選中Device行程串列中的某一個行程,讓Allocation Tracker里面的跟蹤工具處于可用狀態,點擊Stop Tracking來跟蹤程式,過一定時間后,點擊Get Allocations來獲取記憶體分配的訊息就可以查看更為詳細的記憶體分配情況了,如下圖:**
666.png

** Allocation Tracker這個小工具比較簡單, 在這個地方不一一說明了,想學的朋友們自己點擊看看就會知道里面的引數是什么意思了……_………**最后,還是一樣,在記憶體管理方面還要學的東西很多,如果文章中有講的不清楚或不足之處,大家留言批評并提出更好的建議,一定及時改進,在此先謝謝大家啦,吼吼學習學習!大家加油,一起進步!!!

最后

考慮到文章的篇幅問題,我把這些問題和答案以及我多年面試所遇到的問題和一些面試資料做成了PDF檔案,如果有需要的朋友可以私信我【面試】免費領取

點擊這里領取Android面試資料匯總

8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)**

[外鏈圖片轉存中…(img-HbcUao4g-1623508124791)]

[外鏈圖片轉存中…(img-kpXKQolD-1623508124792)]

喜歡的朋友可以關注、轉發、點贊 感謝!

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/287408.html

標籤:其他

上一篇:Android 高級工程師 - 面試總結

下一篇:安卓AIDL跨行程呼叫技術實體(踩坑講解)(兩種方案)(max函式服務|音樂播放服務)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more