天天看點

Android 資源溢出崩潰輕松解

Android 資源溢出崩潰輕松解

作者:位元組跳動終端技術—李權飛

毫無疑問,應用的運作需要占用系統的資源。其中最為人所熟知的資源是記憶體,記憶體溢出便是耳熟能詳的OOM。

常見的簡單OOM一般可以通過堆棧來解決,如Java OOM,一部分可以直接從堆棧中看到哪裡使用了多大記憶體導緻了記憶體溢出,複雜一些的Java OOM,則可以使用其他分析工具來進行處理。但如果堆棧裡看不出來呢?或者它不是Java崩潰呢?

比如下面這樣的Native崩潰,堆棧全是系統堆棧,不花時間去研究就很難确定此崩潰的原因(事實上這個崩潰也是一個OOM)。尤其是,我們并不能說這是系統代碼的問題。

接下來本文将會介紹,對于這類崩潰如何進行識别、以及解決。

Android 資源溢出崩潰輕松解

如下case:

特征很明顯,堆棧全是系統代碼(/system/lib/xxx)。

這時候 無法一眼看出代碼問題,那麼就可以懷疑下記憶體原因。

衆所周知,32位CPU尋址範圍最大可以到2的32次方 = 4GB,其實就是 32位作業系統 最大支援 4G記憶體。

如果你試圖裝過系統就會明白,32位作業系統下,記憶體不可能達到4G以上,一般會是3G左右。

為什麼是3G?因為還有 1G被系統吃掉 了(不一定真的是1G,可多可少但不會差的遠),它們用于作業系統核心相關的運作,如下圖。

Android 資源溢出崩潰輕松解

這裡直接 總結重點 :

32位的App 在 32位的手機 作業系統上使用 超過3G的記憶體 ,極大機率會發生 崩潰 ;

32位的App 在 64位的手機 作業系統上使用 超過4G的記憶體 ,極大機率會發生 崩潰 ;

其中前者容易了解,1G被系統吃了,就剩下了3G;後者是因為64位手機上,系統是64位的,是以不需要跟App搶那4G空間。

至于64位App,可用記憶體已經突破天際(是以開發64位app将會減少大量崩潰)……

需要注意,這裡提到的記憶體,均為 虛拟記憶體 (可以回憶回憶學校學的作業系統知識,網上搜尋瞅瞅)。

這裡需要用到的工具為應用性能監控全鍊路版(APMPlus),APMPlus是位元組跳動應用開發套件MARS下的性能監控産品,通過先進的資料采集與監控技術,為企業提供全鍊路的應用性能監控服務,解決企業對各端監控的需求。具備非侵入式監控、豐富的異常現場還原能力,助力企業提升異常問題排查與解決的效率、優化應用品質,以降低成本提高收入。

經過多年技術積累、億級使用者驗證,APMPlus 集崩潰監控、上報、分析、歸因于一體,可以輕松定位各種線上疑難雜症,更有超詳細性能、卡頓、打點等全流程監控處理工具,覆寫近乎一切線上問題的處理。并擁有多個外部客戶的實踐,如:虎撲、作業幫、甄雲科技等,為企業和開發者提供 一站式APM服務。

我們直接在APMPlus平台中檢視崩潰,點選“Native 資訊 -> Maps詳情”,檢視虛拟記憶體占用。

Android 資源溢出崩潰輕松解

一眼看出,這個記憶體占用明顯接近上一節中提到的 記憶體占滿的門檻值 (32App在64位裝置上最多使用4G記憶體)!此時基本可以确認,該崩潰為記憶體占滿導緻的崩潰,即OOM。

知道是OOM就完了?

再點一個按鈕,直接告訴你怎麼解決:“ Native 資訊 -> Maps智能歸類 ”,檢視 虛拟記憶體占用分布 。

Android 資源溢出崩潰輕松解

我們可以看到,這裡直接提示出三個地方占用的虛拟記憶體最多,分别是Java runtime、Thread、Files;其中 Thread占用最多 ,高達2.59GB!

直接根據提示,逐級展開記憶體占用最多的條目:

Android 資源溢出崩潰輕松解

立即破案:doTestThread線程過多導緻虛拟記憶體占滿!接下來隻需要去代碼裡看,哪裡建立的這個線程,便可進行問題解決。

類似的,一旦在崩潰中發現Maps智能歸類中給出的任意一個條目過高,都可以确認出OOM的原因;假如發現Files條目占用記憶體達到了2G,那麼隻需根據記憶體名即可确認什麼檔案占用記憶體多,進而進行問題定位解決。

其中由于 “ Java runtime”條目占用起點較高 ,其内包含Java堆記憶體等虛拟機自用區域,基本上固定占用1G上下,且一般情況下其占用不會受我們的代碼控制,是以需要注意不要被它混淆了視線, 優先關注其他條目 即可。

另外,Thread記憶體占用過多且需要檢視線程的詳細資訊時,可以在“Native資訊 -> 線程狀态”中檢視。

注:不同App下,虛拟記憶體分布的結果都有不同,具體分析需聯系自身App正常情況下的記憶體分布來确認問題。

平台中目前的記憶體分類方式:

Java runtime:安卓系統Java虛拟機占用,一般App預設會占用1G以上,可降低關注優先級

Native Heap:C代碼使用的堆記憶體大小,如malloc調用配置設定的記憶體等,都會在這裡展現;

Thread:線程使用的記憶體大小,預設情況下每個線程啟動後(Java、Native均如此)便會占用1M記憶體

Files:映射入記憶體中的檔案,一般由C代碼中調用mmap直接加載檔案到記憶體裡,Java中使用FileInputStream不會在這裡展現

Devices:裝置相關記憶體使用

nameless:部分沒有名字的未知記憶體使用

Other:其他未識别記憶體

同樣的,堆棧基本無意義,但有一句看起來能看懂的“Too many open files”。

FD即檔案描述符(File Descriptor),打開一個檔案就占用一個。

看起來沒什麼的,大家讀寫檔案都是正常操作,一個App産生千八百個檔案不過分吧。

但是,系統會 限制單個App打開的 FD 個數 !

該數字在部分低版本安卓機上 一般為1024 ,也就是你打開1024個FD後,就不能再打開了,有時候就會是以 産生崩潰 。

直接點開“ Native 資訊 -> FD 歸類 ”,來确認是不是 FD 過多導緻的崩潰 。

Android 資源溢出崩潰輕松解

很明顯,确實可以看到使用的FD過多,達到了3萬以上。向下滾動可以直接看到App在運作時到底打開了哪些檔案,隻要找到打開的檔案名,便能輕松解決此類崩潰。

Android 資源溢出崩潰輕松解

本文提到的兩種崩潰類型,本質上都是 系統、應用資源不足下 産生的。

資源不足實際上并不會直接導緻崩潰,但是會 使某些系統調用傳回出錯 ,如open打開檔案失敗傳回無效值、malloc配置設定記憶體失敗傳回無效值等。這些傳回的無效值如果在使用時未做合理容錯判斷,則會 引起如空指針等 這樣的代碼錯誤。

更多的崩潰問題歸類及解析,将在應用性能監控全鍊路版(APMPlus)上及後續的文章中進行補充。

如果還未接入使用應用性能監控全鍊路版(APMPlus),也可以立刻開始進行免費試用,目前 APMPlus面向新使用者提供試用30 天的限時免費服務。其中包含 App 監控、Web 監控、Server 監控、小程式監控,App 監控和 Web 監控各500 萬條事件量, Server 與小程式監控限時不限量。

更多産品資訊,歡迎微信進群交流:

Android 資源溢出崩潰輕松解