1. 程式人生 > >Android記憶體洩漏監控和優化技巧總結

Android記憶體洩漏監控和優化技巧總結

前言


對於Android平臺的應用程式來說,記憶體優化一直是個熱門話題,與傳統PC應用程式不同,Android上的應用一旦出現各種異常時系統預設會以最嚴厲的“崩潰”方式反饋給使用者,如果處理不當,將嚴重影響使用者體驗。

叢所周之,移動裝置的軟硬體資源無法與傳統PC相提並論(至少目前是這樣),因而開發人員在編寫應用時,需要有更多技巧、更精深的技術來應對各種局面。這其中尤以記憶體OOM(記憶體溢位)等涉及記憶體洩漏這樣的問題最為常見。

本文著重總結降低應用記憶體佔用的技巧以及對應的解決方案。

先來談談記憶體洩漏的監控機制


記憶體洩露:簡單來說物件由於編碼錯誤或系統原因,仍然存在著對其直接或間接的引用,導致系統無法進行回收。記憶體洩露,容易留下邏輯隱患,同時增加了應用記憶體峰值與發生OOM的概率。它屬於bug issue,是我們一定要修改的。下面是造成記憶體洩露的一些常見原因,但是如何建立一套發現記憶體洩露、解決記憶體洩露的閉環方案,才是我們工作的重點。



1監控方案


Square的開源庫leakcanry是一個非常不錯的選擇,它通過弱引用方式偵查Activity或物件的生命週期,若發現記憶體洩露自動dump Hprof檔案,通過HAHA庫得到洩露的最短路徑,最後通過notification展示。

記憶體洩露判斷與處理的流程如下圖 ,各自執行的程序空間(主程序通過idlehandler,HAHA分析使用的是單獨的程序):

微信在leakcanry推出之前已經有了自己的記憶體洩露監控體系,與leakcanry大致有以下的區別:

事實上,通過對leakcanry做簡單的定製,我們就可以實現以下一個記憶體洩露監控閉環。 

2記憶體洩露後的挽救措施


Activity洩漏會導致該Activity引用到的Bitmap、DrawingCache等無法釋放,對記憶體造成大的壓力,挽救措施是指對於已洩漏Activity,嘗試回收其持有的資源,洩漏的僅僅是一個Activity空殼,從而降低對記憶體的壓力。



做法也非常簡單,在Activity onDestory時候從view的rootview開始,遞迴釋放所有子view涉及的圖片,背景,DrawingCache,監聽器等等資源,讓Activity成為一個不佔資源的空殼,洩露了也不會導致圖片資源被持有。 

總的來說,我們不是隻懂得一些記憶體洩露解決方法就可以,更重要的是通過日常測試與監控,得到記憶體洩露檢測與修改的一整套閉環體系。

如何降低執行記憶體的佔用

1Android系統何時會發生OOM?

2按照慣例:優化Bitmap佔用的記憶體效果最為明顯


說到記憶體,bitmap必然是這裡的大頭。對於bitmap記憶體佔用,想說的有以下幾點:

一個好的imageLoader,可以將2.X、4.X或5.X對圖片載入的處理對使用者隱藏,同時也可以將自適應大小、質量等放於框架中。



3記憶體佔用情況實時監測


對於系統函式onLowMemory等函式是針對整個系統而已的,對於本程序來說,其dalvik記憶體距離OOM的差值並沒有體現,也沒有回撥函式供我們及時釋放記憶體。假若能有那麼一套機制,可以實時監控程序的堆記憶體使用率,達到設定值即關於通知相關模組進行記憶體釋放,這會大大的降低OOM。

- 實現原理:

4程序隔離


對於webview,相簿等,由於存在記憶體系統洩露或者佔用記憶體過多的問題,我們可以採用單獨的程序。微信當前也會把它們放在單獨的tools程序中。

5OOM錯誤資訊上報機制


當系統發生OOM的crash時,我們應當上傳更加詳細的記憶體相關資訊,方便我們定位當時記憶體的具體情況。其他例如使用large heap、inBitmap、SparseArray、Protobuf等不再一一細述,對程式碼採用優化--埋坑--優化--埋坑的方式並不推薦。我們應該著力於建立一套合理的框架與監控體系,能及時的發現諸如bitmap過大、畫素浪費、記憶體佔用過大、應用OOM等問題。

記憶體回收(GC)優化

1頻繁的GC會帶來何種影響


Java擁有GC的機制,不同的系統版本GC的實現可能有比較大的差異。但是無論哪種版本,大量的GC操作則會顯著佔用幀間隔時間(16ms)。如果在幀間隔時間裡面做了過多的GC操作,那麼自然其他類似計算,渲染等操作的可用時間就變得少了。 

2GC的型別介紹


GC的型別有以下幾種,其中GC_FOR_ALLOC是同步方式進行,對應用幀率的影響最大。

- GC_FOR_ALLOC:
當堆記憶體不夠的時候容易被觸發,尤其是new一個物件的時候,很容易被觸發到,所以如果要加速啟動,可以提高dalvik.vm.heapstartsize的值,這樣在啟動過程中可以減少GC_FOR_ALLOC的次數。注意這個觸發是以同步的方式進行的。如果GC後仍然沒有空間,則堆進行擴張

- GC_EXPLICIT:
這個gc是被可以呼叫的,比如system.gc, 一般gc執行緒的優先順序比較低,所以這個垃圾回收的過程不一定會馬上觸發, 千萬不要認為呼叫了system.gc,記憶體的情況就能有所好轉

- GC_CONCURRENT:
當分配的物件大小超過384K時觸發,注意這是以非同步的方式進行回收的.如果發現大量反覆的Concurrent GC出現,說明系統中可能一直有大於384K的物件被分配,而這些往往是一些臨時物件,被反覆觸發了。給到我們的暗示是:物件的複用不夠。

- GC_EXTERNAL_ALLOC(在3.0系統之後被廢了):
Native層的記憶體分配失敗了,這類GC就會被觸發。如果GPU的紋理、bitmap、或者java.nio.ByteBuffers的使用沒有釋放,這種型別的GC往往會被頻繁觸發。

3記憶體抖動


Memory Churn記憶體抖動,記憶體抖動是因為在短時間內大量的物件被建立又馬上被釋放。瞬間產生大量的物件會嚴重佔用記憶體區域,當達到閥值,剩餘空間不夠的時候,會觸發GC從而導致剛產生的物件又很快被回收。即使每次分配的物件佔用了很少的記憶體,但是他們疊加在一起會增加Heap的壓力,從而觸發更多其他型別的GC。這個操作有可能會影響到幀率,並使得使用者感知到效能問題。

通過Memory Monitor,我們可以跟蹤整個app的記憶體變化情況。若短時間發生了多次記憶體的漲跌,這意味著很有可能發生了記憶體抖動。

4GC優化方案


通過Heap Viewer,我們可以檢視當前記憶體快照,便於對比分析哪些物件有可能發生了洩漏。更重要的工具是Allocation Tracker,追蹤記憶體物件的型別、堆疊、大小等。手Q有做一個統計工具,對Allocation Tracker的原始資料,按照(型別&堆疊)的組合(堆疊取棧頂的5層)統計某一種物件分配的大小、次數。同時按照次數、大小的排序,從多/大到少/小結合程式碼分析,並自頂向下的逐輪進行優化。

這樣,我們就可以快速知道發生記憶體抖動時,是因為哪些變數的建立造成頻繁GC。一般來說我們需要注意以下幾個方面:

- 字串拼接優化:

- 資源重用:
建立全球快取池,對頻繁申請、釋放的物件型別重用

- 減少不必要或不合理的物件:
例如在ondraw、getview中應減少物件申請,儘量重用。更多是一些邏輯上的東西,例如迴圈中不斷申請區域性變數等

- 選用合理的資料格式:
使用SparseArray, SparseBooleanArray, and LongSparseArray來代替Hashmap

寫在最後


我們並不能將記憶體優化中用到的所有技巧都一一說明,而且隨著Android版本的更替,可能很多方法都會變的過時。我在想更重要的是我們能持續的發現問題,精細化的監控,而不是一直處於"哪個有坑填哪裡的"的窘況。在這裡給大家的建議有:

  • 率先考慮採用已有的工具;中國人喜歡重複造輪子,我們更推薦花精力去優化已有工具,為廣大碼農做貢獻。生活已不易,碼農何為為難碼農!

  • 不拘泥於點,更重要在於如何建立合理的框架避免發生問題,或者是能及時的發現問題。


當前微信記憶體監控體系中也存在一些不盡人意的地方,在未來的日子裡也同樣需要努力去優化。

公眾號推薦:

相關推薦

Android記憶體洩漏監控優化技巧總結

前言對於Android平臺的應用程式來說,記憶體優化一直是個熱門話題,與傳統PC應

Android記憶體洩漏查詢解決adb shell dumpsys meminfo packagement

1.通過adb shell dumpsys meminfo packageName來檢視記憶體使用狀況 在沒有開啟應用的情況下,該命令返回的資料是這樣的: 2.開啟這個應用的MainActivity,再通過命令檢視: 可以看到打印出來很多的資訊,而對於我們檢

Android記憶體管理機制記憶體洩漏分析及優化

Android中的記憶體管理機制 分配機制 Android為每個程序分配記憶體的時候,採用了彈性的分配方式,也就是剛開始並不會一下分配很多記憶體給每個程序,而是給每一個程序分配一個“夠用”的量。這個量是根據每一個裝置實際的實體記憶體大小來決定的。隨著應用

Android開發-Handler引起的記憶體洩漏-實驗、分析、總結

介紹 最近在惡補Handler的知識,其中就涉及到了Handler引起的記憶體洩露問題,網路上有很多的分析文章。我就按照這些文章的思路,寫程式碼驗證,主要是驗證和記錄。  使用的記憶體檢測工具是:LeakCanary 中文使用說明 英文原文: http://www

SqlServer效能監控優化總結

如何監視和檢視sql server的效能 http://jingyan.baidu.com/article/a378c9609af34eb32828303a.html 開啟sql server studio management 開啟"工具"-"sql server pro

Android 記憶體洩漏總結(超級實用)

Android 記憶體洩漏總結 記憶體管理的目的就是讓我們在開發中怎麼有效的避免我們的應用出現記憶體洩漏的問題。記憶體洩漏大家都不陌生了,簡單粗俗的講,就是該被釋放的物件沒有釋放,一直被某個或某些例項所持有卻不再被使用導致 GC 不能回收。最近自己閱讀了大量相

Android記憶體洩漏與OOM避免措施總結

文章部落格地址:http://blog.csdn.net/gjnm820/article/details/51579080 一、關於OOM與記憶體洩露的概念 我們在Android開發過程中經常會遇到OOM的錯誤,這是因為我們在APP中沒有考慮dalvi

Android O新特性行為變更總結zz

檢測 總結 提示 容易 使用情況 賬號 attr tube strac https://mp.weixin.qq.com/s/Ezfm-Xaz3fzsaSm0TU5LMw 1. Android O 新特性   前段時間解決了幾個 QQ 音樂多窗口屏幕顯示的 bug,雖然

Unity 協程運行時的監控優化

eset 喚醒 end execution iat 分享 部分 handle block 我是快樂的搬運工: http://gulu-dev.com/post/perf_assist/2016-12-20-unity-coroutine-optimizing#toc_0 -

uva 1608 不無聊的序列(附帶常用算法設計優化策略總結

設計 cnblogs 高效 基於 復雜 時間復雜度 出現一次 去除 算法設計 uva 1608 不無聊的序列(附帶常用算法設計和優化策略總結) 紫書上有這樣一道題: 如果一個序列的任意連續子序列中都至少有一個只出現一次的元素,則稱這個序列時不無聊的。輸入一個n個元素的序列

[Android]Android記憶體洩漏你所要知道的一切(翻譯)

以下內容為原創,歡迎轉載,轉載請註明 來自天天部落格:http://www.cnblogs.com/tiantianbyconan/p/7235616.html Android記憶體洩漏你所要知道的一切 原文:https://blog.aritraroy.in/everything-

LeakCanary Android 記憶體洩漏分析利器 原始碼編譯配置mk檔案

LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) LOCAL_SRC_

Android 記憶體洩漏問題

1. 內部類引用導致Activity的洩露     在Android中內部類的引用最常見的是handler,我們經常會這樣寫: private Handler handler = new Handler(){ @Override public void h

Android 記憶體洩漏之LeakCanary

導言: 記憶體管理是android開發效能中重要的一環,而leakCanary是Square開源框架,是一個Android記憶體洩露檢測庫,是個優秀的 記憶體洩露檢測工具,通過它大大降低oom的出現,提高app的質量 釋義: 記憶體洩漏:物件在有限生命週期內還持有引用,沒有被回

Android記憶體洩漏記憶體溢位

Android記憶體洩漏與記憶體溢位 記憶體洩漏 什麼是記憶體洩漏 記憶體洩漏的原因 記憶體洩漏檢測工具LeakCanary Java中的記憶體分配 Java中的四種引用型別 騰訊記憶體洩漏分析

Android記憶體洩漏的檢測工具——LeakCanary

    首先了解什麼是記憶體洩露 http://liuwangshu.cn/application/performance/ram-3-memory-leak.html   1Leakcancary的優勢 LeakCanary是一個視覺化的記憶體

Android記憶體洩漏問題分析及解決方案

大家新年好,由於工作繁忙原因,有好一段時間沒有更新博文了(當然Github是一直都有更新的),趁著年底有點放假時間,我覺得抽空更新下部落格,總結一下工作中最常見記憶體洩漏問題,也是自己之前踩過的坑,為了讓大家少走彎路,系統全面總結一下記憶體洩漏問題分析原因及尋找解決方案。 概念 首

[原始碼和文件分享]基於過載演算法的記憶體洩漏檢測記憶體越界檢測

通過過載`new`,`delete`實現對在動態記憶體分配中記憶體越界和記憶體洩露的自動檢測 1. 記憶體洩漏 1.1 簡介 `記憶體洩漏`是當程式不正確地進行記憶體管理時出現的一種資源洩漏,表現為程式不再需要使用的記憶體空間並沒有及時被釋放掉。記憶體洩漏並非指實體記憶體的消失,而是在程

Android 效能篇 -- 帶你領略Android記憶體洩漏的前世今生

基礎瞭解 什麼是記憶體洩漏? 記憶體洩漏是當程式不再使用到的記憶體時,釋放記憶體失敗而產生了無用的記憶體消耗。記憶體洩漏並不是指物理上的記憶體消失,這裡的記憶體洩漏是指由程式分配的記憶體但是由於程式邏輯錯誤而導致程式失去了對該記憶體的控制,使得記憶體浪費。 Java

android 記憶體洩漏小結

什麼是記憶體洩漏 記憶體洩漏是當程式不再使用到的記憶體時,釋放記憶體失敗而產生了無用的記憶體消耗。記憶體洩漏並不是指物理上的記憶體消失,這裡的記憶體洩漏是值由程式分配的記憶體但是由於程式邏輯錯誤而導致程式失去了對該記憶體的控制,使得記憶體浪費 怎樣會導致記憶體洩漏 資源物件沒關閉