Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android:優化內存

Android:優化內存

編輯:關於Android編程

話說,從mta上報的數據上來看,我們的app出現了3起OOM(out of memery):

java.lang.Throwable: java.lang.OutOfMemoryError
	at com.tencent.stat.a.d.(Unknown Source)
	at com.tencent.stat.g.uncaughtException(Unknown Source)
	at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
	at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
	at dalvik.system.NativeStart.main(Native Method)

從錯誤堆棧是顯然是看不出任何問題的,那麼問題會出現在什麼地方呢?

我們猜測了一下幾種可能?

1、存在內存洩露。

2、不需要的bitmap沒有被釋放。

那麼問題是否就是上面這兩種情況呢?

帶著這個問題,我們首先驗證下,內存是否占用真的很大。

 

首先,開啟android studio內存占用圖標展示工具,可以看到內存占用77M,

\

重啟應用,各頁面點擊一下,相關路徑踩一踩,不踩不知道,一踩就嚇一跳,啟動的時候,直觀的從圖中可以看到,內存占用40M,然而,切換到發現tab,發現內存彪到70M,然後,切換其他頁面,如下圖:

\

比如切換到,消息,我的,等等,發現內存依然,居高不下了,滑動發現頁的時候,內存占用依然有標高的趨勢。

我們使用dumpsys meminfocom.xxx.xxx (app包名),查看內存占用情況如下圖:

\

cat 一下進程,可以看到最大占用(這裡包括虛擬機和原生)如下圖:

\

 

不用說了,這個的優化,那麼怎麼辦?

依然是寄出我們android studio上的內存分析工具,如下圖:

\

首先,GC一下 ,然後在導出hprof文件,進行分析 。首先分析是否存在內存洩露:

\

如上圖,並沒有發現有內存洩露的activity存在,這也歸功於我們平常有事沒事都會隨手分析一下是否有內存洩露,如果有,早就解決了,等不到我。

 

那麼既然沒有內存洩露的Activity,那麼我們何不看一下對象的內存占用情況呢?

如是:如圖

\

這裡,我們很輕易的抓住了第一個凶手,bitmap。

\

其原因是因為這裡做了一個打分的自定義view,這個view的分數是繪制出來的,之所以沒有用字體,是因為引入一個字體庫會增加包大小(雖然可以有些工具可以抽取僅僅需要的字體元素來縮小字體庫,但我們考慮到實現一個打分效果的自定義view的成本也不大,因此並沒有考慮抽取字體庫),得不償失,然而,這個自定義view中每個實例,都擁有0到9加上。的bitmap;

\

然而他被顯示到列表的時候,可想而知,會有多少張圖,優化起來相當簡單,將這些bitmap使用靜態變量保存,這樣所有實例只會公用一份bitmap列表了:

\

,好吧,繼續走查其他對象的內存占用,我們發現:

PopoFeed對象占用內存也較多:但,一層一層的剝下去,最終發現是PopoFeed對象中的User對象裡面的UserTag占用內存較多:

\

可以想象,一個popofeed如果有20多條評論,10幾個人打分,那這樣就有30個User對象在popofeed對象中,30*3K,那就是90K,這些對view展示無用的數據吃內存也是非常恐怖的,所以,拉起後台同學,對返回的數據做了優化。同時,我們發現,返回的數據多,GSON轉model所需要的內存也較多,所以,服務端對返回數據做清洗還是挺有必要的。

,好吧,到了第三階段,我們繼續走查,發現fragment占用內存較多,其實不難推測,使用fragmentManger管理fragment ,你看到的是一個頁面,但其實上,默認是會加載1-2個到緩存中的,從源碼中可以看出:

\

所以,你當前在發現頁,實際上,大廳,消息都已經加載進內存了,那麼這時候的做法就是在重寫setUserVisibleHint

方法,當fragment可見的時候,將數據渲染到view上,當fragment不可見的時候,把view上數據清理掉,不過或許也有更好的方法,如果有,歡迎告訴我~。

然而,還有一個更加可惡的問題,那就是當fragment執行onDestroyView方法後,該fragment並沒有釋放掉內存,這也就是為什麼切換到發現之後,在切換其他fragment內存居高不下的首要原因,我的解決辦法是:

\

因為從引用樹上看到:

\

findFragment被fragmentManger引用著,其在執行onDestroyView的時候,一些該釋放的內存得不到釋放,因此采取以上辦法。

好吧,經過三個小小的優化,我們來看看,內存占用:

對比發現頁:

\

發現頁內存占用現在是 48M,同比之前的77M,減少了37%。

然後切換到我的

\

我們發現內存占用只有28.58M。

對於內存峰值方面的對比,

\

(165516-120792)/165516 = 27%

總結這次的優化:

1、當內存中類的多個對象引用的資源不變的時候,請使用靜態,這樣,這些資源就只有一份,減少不必要的內存占用。

2、json轉model是一個很耗時的過程,減少json中不必要的字段,不僅可以加快json轉model的時間,還能降低內存占用。

3、fragment不可見的時候,實際上可能還占用著你的內存,要懂得小心釋放不必要的內存。

 

騰訊自主研發,榮獲2015年十佳組件第一名的“tMemoryMonitor”內存洩漏分析工具。該騰訊內部工具已經在騰訊WeTest官網內免費開放給用戶使用

TMM下載地址:http://wetest.qq.com/cloud/index.php/index/TMM

【工具簡介】

tMemoryMonitor簡稱TMM,是一款運行時C/C++內存洩漏檢測工具。TMM認為在進程退出時,內存中沒有被釋放且沒有指針指向的無主內存塊即為內存洩漏,並進而引入垃圾回收機制,在進程退出時檢測出堆內存中所有沒有被引用的內存單元,因而內存洩漏檢測准確率為100%。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved