移動App性能評測與優(yōu)化

本文是《移動App性能評測與優(yōu)化》的讀書筆記。
PS:說是讀書筆記,其實(shí)就是摘錄蛤奢。

移動App的性能測試主要包括:內(nèi)存使用情況、電量消耗陶贼、功能的流暢度等啤贩;

1. 內(nèi)存

1.1 內(nèi)存的主要組成索引:

  • Native Heap : Native 代碼分配的內(nèi)存,虛擬機(jī)和Android框架本身也會分配拜秧;

  • Dalvik Heap : Java 代碼分配的對象痹屹;

  • Dalvik Other : 類的數(shù)據(jù)結(jié)構(gòu)和索引;

  • so mmap : Native 代碼和常量枉氮;

  • dex mmap :Java 代碼和常量志衍;

1.2 內(nèi)存測試工具

  • Android Studio / Memory Monitor : 觀察 Dalvik 內(nèi)存;

  • dumpsys meminfo : 觀察整體內(nèi)存聊替;

  • smaps : 觀察整體內(nèi)存的詳細(xì)組成楼肪;

  • MAT : 詳細(xì)分析 Dalvik內(nèi)存;

1.3 一個(gè)類的內(nèi)存消耗

虛擬機(jī)在創(chuàng)建對象時(shí)的操作:

  • loadClass惹悄,將類信息從 dex 文件中加載進(jìn)內(nèi)存:

    • 讀取 .dexx mmap 中 class 對應(yīng)的數(shù)據(jù)春叫;

    • 分配 native-heap 和 dalvik-heap 內(nèi)存創(chuàng)建 class 對象;

    • 分配 dalvik-LinearAlloc 存放 class 數(shù)據(jù)泣港;

    • 分配 delvik-aux-structure 存放 class 數(shù)據(jù)暂殖;

  • new instance 操作,創(chuàng)建對象實(shí)例

    • 執(zhí)行 .dex mmap 中 <clinit> 和 <init> 的代碼当纱;

    • 分配 delvik-heap 創(chuàng)建 class對象實(shí)例呛每;

dex mmap在Android應(yīng)用中的作用是映射classes.dex文件

1.4 dex 優(yōu)化

省略掉dex的文件結(jié)構(gòu)(自行查閱)

為了節(jié)省空間,dex將原先在 class 文件中重復(fù)的信息集中放置在一起惫东,并以索引和指針的形式支持快速訪問莉给。

dex 文件中數(shù)據(jù)基本是按類名的字母順序進(jìn)行排列的,這樣同樣包名的類會排在一起廉沮,但程序?qū)嶋H執(zhí)行時(shí)颓遏,同一個(gè)包下的類并不會全部調(diào)用到,而是跨包進(jìn)行交互滞时,但 mmap 加載了整個(gè)頁面叁幢,可能會有很多無用的數(shù)據(jù)。

優(yōu)化;

在APK的編譯流程中坪稽,Proguard 混淆工具正好是能夠?qū)︻惷M(jìn)行修改的曼玩,可以根據(jù)程序運(yùn)行時(shí)的邏輯鳞骤,將那些會互相調(diào)用的類改為為同一個(gè) package 名,這樣就可以使它們的數(shù)據(jù)排布在一起黍判。

1.5 MAT(Memory Analyzer Tool)

使用MAT來分析應(yīng)用的內(nèi)存使用情況豫尽。通常在使用MAT打開hprof文件后,能夠在首頁看到Top Comnsumers和 component Report等功能顷帖,我們可以快速定位一些大塊的內(nèi)存消耗美旧。但我們在分析時(shí)會發(fā)現(xiàn)系統(tǒng)資源類占據(jù)了很大一部分內(nèi)存,因此為去除這部分對分析的干擾贬墩,我們在使用AndroidSDK提供的hprof-conv轉(zhuǎn)換時(shí)需要增加一個(gè)參數(shù):


hporf- conv [-z] <infile><outfile> -z:exclude non-app heaps,such as Zygote

如果hprof文件是已經(jīng)轉(zhuǎn)換過的榴嗅,則可以使用OQL:


//在數(shù)據(jù)中尋找應(yīng)用的Application類對象,將對象地址轉(zhuǎn)換為十進(jìn)制后輸入以下查詢語句:

select * from instanceof java.langObject s where s.@objectAddress> 1107296256

//(后面那串?dāng)?shù)字應(yīng)該是Application類對象的地址)

采用這兩種方法后陶舞,再使用MAT來分析就可以比較容易發(fā)現(xiàn)自身代碼的內(nèi)存問題嗽测。

1.6 測試經(jīng)驗(yàn)

  • MAT 是探索 Java 堆并發(fā)現(xiàn)問題和好幫手,能夠迅速發(fā)現(xiàn)常見的圖片和大數(shù)組等問題肿孵;

  • 內(nèi)存碎片問題一般隱藏在對象的地址中唠粥;

  • 如需要測試非 Dalvik部分,有必要了解 Linux 的進(jìn)程和內(nèi)存原理颁井、內(nèi)存共享機(jī)制厅贪,熟悉常用命令行工具;

  • 內(nèi)存分配的最小單位是頁面雅宾,通常為4KB养涮,這個(gè)限制會引發(fā)各種問題;

1.7 性能優(yōu)化

  • 盡量不要在循環(huán)中創(chuàng)建很多臨時(shí)變量眉抬;

  • 可以將大型的循環(huán)拆散贯吓、分段或者按需執(zhí)行;

  • 引入SDK庫和調(diào)用新的系統(tǒng)API里需要考慮成本蜀变;

  • 除了Dalvik堆內(nèi)存悄谐,還有其他類型的內(nèi)存在了解了原理后也能夠進(jìn)行分析和優(yōu)化;

  • dex 文件有很多優(yōu)化空間库北。在仔細(xì)統(tǒng)計(jì)并調(diào)整了dex文件的順序后爬舰,往往可以節(jié)約1M以上的 mmap 內(nèi)存;

2. 耗電

在保證用戶的必要體驗(yàn)前提下寒瓦,盡可能減少不必要的操作情屹。幾個(gè)優(yōu)化方法:

方法一:CPU時(shí)間片

當(dāng)應(yīng)用退到后臺運(yùn)行時(shí),盡量減少應(yīng)用的主動運(yùn)行杂腰,當(dāng)檢測到CPU時(shí)間片消耗異常時(shí)垃你,深入線程進(jìn)行分析;

使用 DDMS 的 traceview 工具:獲取進(jìn)程運(yùn)行過程中的 traceview,定位CPU占用率異常的方法。

方法二 wake lock

前臺運(yùn)行時(shí)運(yùn)不要去注冊 wake lock惜颇。 此時(shí)注冊沒有任何意義皆刺,卻會被計(jì)算到應(yīng)用電量消耗中。后臺運(yùn)行時(shí)凌摄,在保證業(yè)務(wù)需要的前提下羡蛾,應(yīng)盡量減少注冊 wake lock;降低對系統(tǒng)的喚醒頻率锨亏,使用 partial wake lock 代替 wake lock林说;

方法三 傳感器

合理地設(shè)置 GPS 的使用時(shí)長和使用頻率;

方法四 云省電策略

可考慮定期上報(bào)用戶手機(jī)電量數(shù)據(jù)的方式來分析問題屯伞;

3. 流暢度

3.1 分析工具

  • hierarchy Viewer ,幫助我們?nèi)シ治鯱I布局的情況豪直;

  • Tracer for OpenGL ES,可以記錄和分析APP每一幀的繪制過程劣摇,以及列出所有乃至的OpenGL ES 的繪制函數(shù)和耗時(shí);該工具操作后會生成一份記錄App繪制過程和gltrace文件弓乙,

  • Lint 掃描末融,發(fā)現(xiàn)代碼中的流暢度性能問題;

  • Traceview,跟蹤程序性能暇韧,具體到每一個(gè)函數(shù)的耗時(shí)和調(diào)用次數(shù)

  • Systrace 勾习,獲取App運(yùn)行時(shí)線程的信息以及Api執(zhí)行情況

< merge > 標(biāo)簽:用于減少View樹的層次來優(yōu)化 Android 的布局,通過該標(biāo)簽可以把 < merge > 標(biāo)簽里的UI合到上一層的 layout中懈玻。

< ViewStub> 標(biāo)簽巧婶,最大的優(yōu)點(diǎn)是當(dāng)你需要時(shí)才會加載,使用它并不會影響UI初始化時(shí)的性能涂乌。各種不常用的布局可以使用該標(biāo)簽來減少內(nèi)存使用量艺栈,加快渲染速度。< ViewStub> 是一個(gè)不可見的湾盒,大小為0的View湿右。

對于不常用的 UI 可以考慮使用 < ViewStub> 標(biāo)簽替代 GONE 來提高 UI 性能:

將 View 的可見性設(shè)置為 GONE,在 Inflate 布局時(shí) View仍然會被 Inflate罚勾,也就是說仍然會創(chuàng)建對象毅人,會被 實(shí)例化。而 ViewStud 是一個(gè) 輕量級的 View尖殃,它是一個(gè)看不見丈莺、不占布局位置、占用資源非常小的控件分衫。

3.2 Perforjmance中的16個(gè)問題

  • DrawAllocation: 避免在繪制或者解析布局(draw/layout)時(shí)分配對象场刑,比如在Ondraw()中實(shí)例化 Paint 對象;

  • Wakelock, 手機(jī)不能進(jìn)入休眠狀態(tài),導(dǎo)致手機(jī)一直保持在高耗電狀態(tài)牵现;

  • Recycle :某些資源铐懊,比如 TypedArrays 、 VelocityTrackers瞎疼,用完后應(yīng)該被回收科乎,但是忘記回收。

  • ObsoleteLayoutParam : Layout中無用的參數(shù)贼急;

  • UseCompoundDrawables,可優(yōu)化的布局茅茂;

  • HandlerLeak: Handler 的使用不當(dāng)導(dǎo)致內(nèi)存泄漏;

  • UseSparseArrays ,盡量用 Android 的SparseArray 代替 Hashmap;

  • UseValueOf : 需要常量對象時(shí)太抓,不應(yīng)該直接 new, 應(yīng)該使用 ValueOf 轉(zhuǎn)換空闲。比如需要整數(shù) 42 的對象,不要直接用 new Integer(42),應(yīng)該用 Intener.vallueOf(42),這樣可以省內(nèi)存走敌;

  • DisableBaselineAlignment: 如果 LinearLayout 被用于嵌套 layout空間 計(jì)算碴倾,它的 android:baselineAligned 屬性應(yīng)該設(shè)置成 false ,以加速 layout 計(jì)算掉丽;

  • InefficientWeight : 當(dāng)線性布局里只有一個(gè)控件跌榔,并且使用了weight 屬性,最好把 weidth 和 height 設(shè)置為0捶障,這樣可以省略布局的 measure 過程僧须;

  • FloatMath, 使用 FloatMath 代替 Math;

  • NestedWeights : 避免嵌套 weight 项炼,那將拖累執(zhí)行效率担平。

  • UnusedResources / UnusedIds, 未被使用的資源會使程序變大,并且編譯速度降低锭部;

  • Overdraw: 如果為 RootView 指定一個(gè)背景 Drawable,會先用Theme 的背景繪制一遍驱闷,然后才用指定的背景,這就是所謂的 “Overdraw” 空免,可以設(shè)置 theme 的background 為 null 來避免空另;

  • UselessLeaf / UselessParent : View 或 view 的父親沒有用,應(yīng)該把它移除蹋砚,避免影響加深布局的層次扼菠;

  • UnusedNamespace : 有些代碼沒必要使用 namespace ,會影響代碼執(zhí)行效率;

4. 網(wǎng)絡(luò)優(yōu)化

考慮點(diǎn):

  • 分小片傳輸一個(gè)文件(圖片)坝咐,這樣當(dāng)某一個(gè)分片失敗時(shí)循榆,只需要重傳這一個(gè)分片就可以炼鞠,而不用重傳整個(gè)文件胰耗;

  • 不同類型的移動互聯(lián)網(wǎng)下的分片初始大小應(yīng)該有所不同;

  • 在上傳一個(gè)文件的過程中穗泵,應(yīng)當(dāng)盡可能動態(tài)增大分片大小,以減小分片數(shù)量盗尸;

  • 確定每個(gè)分片是否要繼續(xù)增大之前柑船,要檢查網(wǎng)絡(luò)類型是否發(fā)生了改變;

  • 分片一旦傳輸失敗泼各,應(yīng)當(dāng)使用該網(wǎng)絡(luò)下的初始分片大小進(jìn)行重試鞍时;

重點(diǎn)優(yōu)化優(yōu)質(zhì)網(wǎng)絡(luò)下的傳輸速度,而不特意優(yōu)化差網(wǎng)絡(luò)下的速度扣蜻;

5. apk瘦身

5.1 瘦身關(guān)鍵點(diǎn):

  • 代碼部分:冗余代碼逆巍、無用功能、代碼混淆莽使、方法數(shù)縮減锐极;

  • 資源部分:冗余資源、資源混淆芳肌、圖片處理(壓縮溪烤、圖片轉(zhuǎn)換、點(diǎn)9圖化等)庇勃;

  • 對整個(gè)安裝包做7zip極限壓縮;

Android 系統(tǒng)安裝一個(gè)應(yīng)用的過程中槽驶,其中有一步是對 Dex 進(jìn)行優(yōu)化责嚷,優(yōu)化的過程是使用專門的工具 DexOpt。DexOpt 是在第一次加載Dex文件的時(shí)候執(zhí)行的掂铐。在DexOpt的過程會生成一個(gè)ODEX文件罕拂。

早期的 DexOpt 有兩個(gè)問題:

  • DexOpt 會把每一個(gè)類的方法的id 檢索起來,存在一個(gè)鏈表的結(jié)構(gòu)里的全陨,但是這個(gè)鏈表的長度是用一個(gè) short 類型來保存的爆班,導(dǎo)致了方法 id 的數(shù)目不能超過 65536(2^16);

  • DexOpt 使用 LinearAlloc 來存儲應(yīng)用的方法信息,LinearAlloc是一個(gè)固定大小的緩沖區(qū)(4辱姨,5柿菩,8,16)雨涛,當(dāng)方法數(shù)量過多也會導(dǎo)致超出緩沖區(qū)大小時(shí)枢舶,也會造成 DexOpt 崩潰;

5.2 縮減方法數(shù)的方法

  • 避免在內(nèi)部類中訪問外部類的私有方法或變量替久;當(dāng)在 java 內(nèi)部類(包括 匿名內(nèi)部類)中訪問 外部類的私有方法或變量時(shí)凉泄,編譯器會生成額外的方法;

  • 避免調(diào)用派生類中的未被覆蓋( override) 的方法蚯根;避免在派生類中調(diào)用未覆蓋的基類的方法后众;避免用派生為對象調(diào)用派生類中未被覆蓋的基類的方法。因?yàn)楫?dāng)調(diào)用派生類中的未被覆蓋的方法時(shí),會多產(chǎn)生一個(gè)方法數(shù)蒂誉;

  • 去掉部分類的get 教藻、set 方法;

5.3 代碼混淆

代碼混淆( Obfuscated code)也叫花指令;對代碼進(jìn)行 Proguard 后拗盒,也可以比較大的減小代碼的體積(即 dex 的體積)怖竭;

6 參考文獻(xiàn):

1 移動App性能評測與優(yōu)化

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市陡蝇,隨后出現(xiàn)的幾起案子痊臭,更是在濱河造成了極大的恐慌,老刑警劉巖登夫,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件广匙,死亡現(xiàn)場離奇詭異,居然都是意外死亡恼策,警方通過查閱死者的電腦和手機(jī)鸦致,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涣楷,“玉大人分唾,你說我怎么就攤上這事∈ǘ罚” “怎么了绽乔?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長碳褒。 經(jīng)常有香客問我折砸,道長,這世上最難降的妖魔是什么沙峻? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任睦授,我火速辦了婚禮,結(jié)果婚禮上摔寨,老公的妹妹穿的比我還像新娘去枷。我一直安慰自己,他們只是感情好是复,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布沉填。 她就那樣靜靜地躺著,像睡著了一般佑笋。 火紅的嫁衣襯著肌膚如雪翼闹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天蒋纬,我揣著相機(jī)與錄音猎荠,去河邊找鬼坚弱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛关摇,可吹牛的內(nèi)容都是我干的荒叶。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼输虱,長吁一口氣:“原來是場噩夢啊……” “哼些楣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宪睹,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤愁茁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后亭病,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹅很,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年罪帖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了促煮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡整袁,死狀恐怖菠齿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坐昙,我是刑警寧澤绳匀,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站民珍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盗飒。R本人自食惡果不足惜嚷量,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逆趣。 院中可真熱鬧蝶溶,春花似錦、人聲如沸宣渗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痕囱。三九已至田轧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鞍恢,已是汗流浹背傻粘。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工每窖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弦悉。 一個(gè)月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓窒典,卻偏偏與公主長得像,于是被迫代替她去往敵國和親稽莉。 傳聞我的和親對象是個(gè)殘疾皇子瀑志,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容