1. 內存性能評估緩存
應用包(debug版)體積偏大,存在較多的內存泄露、OOM隱患、UI層級過深等問題,同時存在較多的其餘各類內存問題。微信
應用apk包體積約50MB,安裝到手機後,佔用手機約99.50MB存儲空間,運行時佔用內存空間約160MB的內存空間,其中Native內存佔用約65MB,Dalvik內存佔用約6MB,從目前的業務複雜度分析,99.50的存儲空間過於浪費,後續優化應針對apk降size,減少包體積。本次分析主要針對內存泄漏和OOM兩大類內存問題進行分析,應用目前存在比較多的內存泄漏和OOM隱患。框架
內存泄露問題主要分佈在(匿名)內部類/Callback間接持有Activity引用、Handler泄漏、static成員泄漏是項目工程中三塊主要的內存問題,在本次發現內存問題總數中佔比約55%。ide
OOM問題隱患主要分佈在Bitmap未及時釋放,在本次發現內存問題總數中佔比約38%。工具
有些UI界面層級多達18層。性能
2.內存使用分析測試
本項分析的目的,在於概覽應用在使用過程當中佔用內存的概況,從整體角度瞭解應用耗用內存的程度,大概在哪些地方耗用內存。優化
表1 描述了應用數據使用概況,應用安裝後的大小爲99.50MB,持久化數據存儲空間佔用空間量級在數MB左右。
表1 應用數據使用統計
編號 |
應用場景 |
應用大小(MB) |
數據大小(MB) |
1 |
安裝完畢,當即查看應用數據佔用 |
99.50 |
0.04 |
2 |
操做應用一段時間 |
99.50 |
1.36 |
3 |
緊接第2項,靜置約60分鐘後 |
99.50 |
1.53 |
4 |
緊接第2項,靜置約240分鐘後 |
99.50 |
1.53 |
表2描述了市面上經常使用大型成熟應用大小統計,從中可看出本應用的體積存在很大的壓縮空間。
表2 大型成熟應用大小統計
編號 |
大型成熟應用 |
應用大小(MB) |
應用版本 |
1 |
今日頭條 |
87.14 |
6.8.5 |
2 |
手淘 |
162 |
7.11.20 |
3 |
惟品會 |
173 |
6.25.3 |
4 |
微信 |
185 |
6.7.2 |
5 |
高德地圖 |
214 |
8.61.1.1456 |
此項主要分析應用業務佔用內存的概況,以一條比較佔用內存的業務操做路徑爲例, 表3展現了應用業務的內存佔用狀況。
從表3可知,應用的內存佔用總大小在155~160MB間,其中佔用Native約60多MB的空間,而Dalvik空間佔用約5.7MB左右,近50%的內存佔用來自Native。
表3 應用內存使用統計(參考)
編號 |
總大小(MB) |
Dalvik(MB) |
Native (MB) |
1 |
123.13 |
5.76 |
62.88 |
2 |
156.17 |
5.38 |
61.25 |
3 |
159.44 |
5.78 |
62.97 |
4 |
159.20 |
5.63 |
61.09 |
附註:內存檢測路徑: 首頁->音箱->在線音樂->歌單詳情
表2中第1次的測試數據同另外3次測試數據有較大的差別,表3描述了這個差別的來源。
表4 致使表3數據較大差別來源
編號 |
.so mmap(MB) |
GL mtrack(MB) |
1 |
8.66 |
10.50 |
2 |
12.80 |
38.01 |
3 |
12.85 |
39.63 |
4 |
12.79 |
38.54 |
3. 內存泄露分析
歷史內存泄露問題單共10例,問題緣由主要集中在非靜態內部類實例、匿名內部類實例、Callback實例直接/間接引用局部Context這幾種狀況。
歷史問題單連接以下:
http://jira.company.me/browse/IOT-7792
http://jira.company.me/browse/IOT-7791
http://jira.company.me/browse/IOT-7219
http://jira.company.me/browse/IOT-7019
http://jira.company.me/browse/IOT-6672
http://jira.company.me/browse/IOT-5887
http://jira.company.me/browse/IOT-5886
http://jira.company.me/browse/IOT-5826
http://jira.company.me/browse/IOT-5779
http://jira.company.me/browse/IOT-4441
本次內存分析,共處理42例內存問題,分別以下:
5個內存問題JIRA單;
lint性能檢查9個handler內存泄露、1個在onDraw內分配內存、1個cursor未recycle、7個static成員泄露;
代碼Review檢查2個Callback內存泄露、13個Bitmap未即時釋放、2個Drawable重複內存申請;
工具檢查1個Activity泄露;
開發羣上報1個Activity has leaked window內存泄露及崩潰。
表5對本次發現的內存問題進行了分類彙總,內存泄漏問題38例,OOM問題1例,其餘內存問題13例。
表5中的內存泄漏共38例,其中包括13例Bitmap未即時釋放,原則上Bitmap未即時釋放不是內存泄漏,但考慮到Bitmap是內存消耗大戶,中短期內得不到釋放,極容易致使OOM,故本分析文檔將Bitmap未及時釋放概括爲內存泄漏門類。
在本次對內存的分析中,實際發現的Bitmap未及時釋放的問題數遠不止13例,因後續實施了問題補救措施——引入LruCache與OSS構建二級緩存,因此至關一部分的Bitmap沒釋放的問題點可暫時忽略。
表5 內存問題統計表
編號 |
檢查類型 |
內存泄漏 |
OOM |
其餘內存問題 |
1 |
JIRA單 |
4 |
1 |
|
2 |
lint檢查 |
17 |
|
1 |
3 |
代碼Review檢查 |
15 |
|
2 |
4 |
工具檢查 |
1 |
|
|
5 |
開發羣上報 |
1 |
|
|
合計 |
|
38 |
1 |
3 |
圖1描述了內存泄露問題分佈,從中可分析出Handler泄漏、Bitmap未及時釋放、static成員泄漏是項目工程中三塊主要的內存問題,佔比約85%。
圖1內存泄露問題分佈圖
圖2描述了各階段上報的內存問題數,從中可分析出在編碼階段,更容易發現內存問題。
圖2各階段上報內存問題數
基礎業務模塊採用LruCache與OSS加載Bitmap,而設備模塊採用Glide管理Bitmap,v1.1版本存在兩個圖片管理框架,後期需合併爲一個圖片管理框架。
項目代碼中還存在經圖形變換/未經緩存框架產生的Bitmap,沒有及時釋放。
應用中存在大量Callback,這些Callback的實現當中,不排除有爲數很多的內存泄露隱患,絕大多數都和Activity等局部Context存在引用關係, 建議採用加入消息機制以杜絕此類內存泄露隱患。
本次內存優化,因爲時間因素,以及項目UI界面需從新適配,故本次內存優化只是檢查了UI層級嵌套狀況,並無對UI層級嵌套進行優化。
圖3描述了較複雜頁面及對應的UI層級,圖3左邊爲實際展現的UI界面,圖3右邊爲左邊UI的UI層級,從中可看出圖3的UI層級不低於18層級。
注意:圖3中的層級從第4層開始算起,前面3層爲系統生成的固定UI層級。
圖3較複雜頁面及對應的UI層級
圖4描述了較簡單頁面及對應的UI層級,從中可看出圖4的UI層級爲7層。
圖4簡單頁面及對應的UI層級
4.總結
本次內存分析,解決了必定量的內存泄漏和OOM隱患,但應用內仍是存在爲數很多的內存泄漏點和OOM隱患,要進一步解決內存問題,須要普及內存優化知識和觀點,避免在新開發的模塊功能埋入內存隱患,同時持續地對內存使用追蹤和優化。