Android中內存優化的那些事 - 一個有關圖片的優化記錄

客服羣裏叫喊着:這個用戶圖片不顯示了,那個用戶圖片也不顯示了。我拿着手上一切正常的測試機,what the hell……html

默默地打開bugly。java

滿園春色關不住,遍地內存溢出來!是的,又闖禍了!android

內存問題永遠是既陌生又熟悉的話題,並且大多數都發生在一個叫做用戶家的手機上。安卓系統自己不斷的在優化,三方框架也逐漸成熟,外加手機廠商的大內存加持,彷佛內存問題變得少見,但仍是不能忽視。數組

藉着此次修復內存問題的記錄,分享一些「自覺得」的解決思路,僅供參考。ok,let’s go!網絡

修復問題的三部曲,先復現,再定位,最後修復。框架

復現

估計有的人會說,異常現象都在那,有啥好復現的,衝進代碼直接開幹。eclipse

修復bug永遠是個驚心動魄的事,稍微一不當心就有可能天崩地裂。不是修復不徹底,就是引入新問題。從原由開始瞭解整個原因,一方面能加深對問題的理解,同時確保最終能驗證問題是否獲得修復。工具

內存的問題常常發生在一些比較特殊的環境下,並且不少時候不必定是必現,每每體如今一些中低端機型上。因此從機型上入手可能會是一個不錯的選擇。測試

最終,經過bugly查到了對應的問題機型及系統版本,上各種雲測平臺找到了臺雲測試機。按照進入問題頁面的幾個固定流程,反覆執行,最終鎖定了復現流程。字體

定位

知道問題如何復現,接下來就是定位問題到底出在哪。一般內存的問題,會碰到兩種狀況:

  1. 內存堆積:因爲特殊狀況形成的頁面關閉但資源還遺漏在內存中。
  2. 內存高佔用:因爲業務須要或者使用不當致使內存佔用量太高。

咱們先來看看此次的問題屬於哪一種狀況。

在Android Studio2.3及以前版本上自帶的Android monitor中,能夠直觀的反應出當前應用的總體內存使用水平。[如何使用工具的分享估計你們都看膩了,此次就再也不重複了。]

142MB!!!!進入事故現場以前就已經被佔用了這麼多內存。難怪以後會內存異常。看來此次要先解決內存高佔用的問題,咱們先要詳細的瞭解內存的具體狀況,才知道從哪下手去解決,不管是避免無心義的使用或者優化必要的佔用。

先強制gc一下,而後dump java heap,看一下總體內存裏的狀況,按照shallow size排序。

首當其衝的byte數組映入眼簾,你們都明白的,bitmap一直都是大客戶。咱們接着分析下byte[]中的各個對象。

從數據上看,有不少大小相同的內存使用,從理論上看應該是有不少尺寸相同的圖片。可爲何會有這麼多呢?是相同的圖片重複了?or other?

所謂耳聽爲虛眼見爲實,若是能看到這些圖片長什麼樣,是否就容易作出對應的判斷了?來,開始行動:
來自Gracker的Android內存優化之三:打開MAT中的Bitmap原圖 | Performance

感謝Gracker的分享,Get到一個新技能。具體流程參見傳送門。主體思路就是經過MAT將對應的byte數組另存爲圖片原始文件,再用對應的工具打開預覽便可。不過我記得之前Android Studio是能夠直接看的,可如今不知道跑哪了。

步驟一:

由於Android Studio dump出來的文件mat是沒法直接打開的,因此須要作一次轉換。在Captures中找到剛剛dump出來的prof文件。右鍵 -> Export to standar .hprof 便可。

步驟二:

經過MAT Eclipse Memory Analyzer Open Source Project 打開。

步驟三:

右鍵想要查看的對象 -> Copy -> Save Value To File。保存爲xxx.data。他推薦使用Gracker分享中的gimp。Photoshop不肯定是否是我使用方式有問題,在驗證的時候一直沒法正常顯示。

步驟四:

查看對應圖片的相關屬性,主體是要寬高,由於上一步中保存的是圖片的原始格式文件,其中不包含對應的參數信息,因此在導入gimp中須要指定對應的參數。

步驟五:

打開gimp GIMP - Downloads. 而後打開剛剛導出的問題。圖像類型根據實際的來,通常都是8888或者565,選擇RGB Alpha或者RGB565。而後寬度與高度填寫剛剛查詢到的參數。最後點擊open就能看到實際的圖片。

經過這個方式,能夠直觀的查看到內存中圖片的實際狀況。而後咱們就能夠進一步分析產生問題的實際緣由。

經過以上方式,定位到了3個問題:

  1. 有大量圖片資源佔用,首頁確實有好多圖。
  2. 有暫未使用到的圖片資源佔用(gone狀態)。
  3. 有大量蒙版圖片佔用,由於設計師要求的效果。

解決 - 大量圖片佔用

對於大量圖片佔用的問題,其實從如下幾個個方向來看思考問題。

  1. 從效果設計的角度來避免,儘量的少使用滿屏圖片的方式來處理需求。但這方面我我的主張尊重設計師,專業的事情交給專業的人去處理。
  2. 圖片資源自己,在知足效果的前提下,儘量的選用RGB565,也許少許圖片不明顯,但在量大的狀況下,節省的內存資源仍是很客觀。
  3. 圖片資源在不使用的時候及時釋放。

結合以上方向來看下咱們遇到的問題。設計角度目前沒法調整,原因都是淚,這裏就很少說了。資源自己已是RGB565。圖片的釋放應該是fresco的強項,可從現象上看彷佛並無。看來問題可能出在這,回ui頁面上瞄一眼,明白了。

viewpager + fragment + recyclerview,至關於大量圖片都屬於使用狀態,因此fresco不會去釋放對應的資源。

臨時解決方案:
爲了確保核心邏輯的順利,經過RxBus的方式,在進入和退出核心頁面時發送Event事件,而後在大量使用圖片的頁面註冊接收此係列事件,遍歷全部SimpleDraweeView,調用其Controller的onDetach或onAttach來,從而實現圖片資源引用的臨時釋放和加載恢復。

爲何是臨時解決方案,由於我總以爲是一種取巧的方式,理論上看。是不該該直接調用方法來插手fresco的管理流程。因此此處留坑,以後再次深刻了解fresco的原理後再回填,也但願你們提些建議或者意見。

解決 - 暫未使用到的圖片資源佔用

每一個頁面中,都有處理網絡異常及相關數據加載異常的提示。原先的處理方式是經過include統一導入後隱藏,在遇到異常的時候才顯示出來。問題就出在這,這些異常提示自己是小几率觸發,但經過include標籤導入的話,會直接實例化完成,佔用內存資源。

臨時解決方案:
改用ViewStub標籤,實現按需加載。

爲何又是臨時解決方案呢,由於有些機型在黑屏狀態下是切斷wifi的,當從新進入應用的時候都會通過一個聯網的過程,因此會先觸發聯網異常,ViewStub只能加載一次,加載完後就佔用內存了。

解決 - 蒙版圖片

以前爲了在圖片上顯示文字但又不想被圖案所影響,因此在上面加一層陰影蒙版來保證字體的顯示效果。習慣用fresco:overlayImage的方法來實現。但這種實現方式會形成蒙版自己是一個獨立的內存資源。

解決方法:
嘗試經過Processor的方式,預先把蒙版與要顯示的圖片合成,使得在內存中只保留一份資源。

結果

經過以上優化方式,一樣的機型再次檢測,內存佔用下來了....

總結

此次從內存高佔用入手,解決了因爲內存使用量太高致使的內存溢出。等以後遇到內存遺留問題時,再來補下文。

內存問題的排查與解決算是一個老生常談的話題,由於適配等等狀況每每又是一個比較棘手的問題。開發的時候很難發現,因此建議一個需求完成後都例行的檢查下內存情況,看下是否有問題後者須要調整的部分。

相關文章
相關標籤/搜索