Android 系統性能優化(28)---Android 效能優化工具集合
阿新 • • 發佈:2019-01-26
磁碟
- 檔案讀寫:每次開啟、關閉或者讀寫檔案,作業系統都需要經過從使用者態轉換為核心態的切換,這種狀態的切換本身是很消耗效能的,所以為了提高檔案的讀寫效率,就需要儘量減少使用者態和核心態的切換。使用快取可以避免重複讀寫,對於需要多次訪問的資料,在第一次取出資料的時候,將資料放在快取中,下次再訪問的時候,就可以從快取中取出來。
- Android手機裡面的
libsqlite.so
呼叫系統的pread64
和pwrite64
函式進行I/O
操作。 序列化:
ObjectOutputStream
在序列化磁碟的時候,會把記憶體中的每個物件儲存到磁碟,在儲存物件的時候,每一個數據成員會帶來一次I/O操作。因此,在使用ObjectOutputStream
ObjectOutputStream
上面再封裝一個輸出流ByteArrayOuputStream
先將物件序列化後的資訊寫到快取區中,然後再一次性地寫到磁碟上。序列化磁碟讀寫方式 優化前 優化後 序列化寫磁碟 ObjectOutputStream BufferedOutputStream + ObjectOutputStream ByteArrayOutputStream + ObjectOutputStream 序列化讀磁碟 ObjectInputStream BufferedInputStream + ObjectInputStream ByteArrayInputStream + ObjectInputStream 序列化磁碟讀寫方式 優化前後 I/O次數 耗時(ms) 序列化寫磁碟 優化前 499 162.8 優化後 1 87.3 序列化讀磁碟 優化前 719 171.8 優化後 1 109.9 - Buffer緩衝區大小:在讀/寫時使用緩衝區可以減少讀寫次數,從而減少了切換核心態的次數,提高讀/寫效率,根據實際經驗,這裡推薦使用的Buffer大小為8KB,這和Java預設的Buffer大小一致,Buffer大小至少應為4KB。當然,Buffer也不是越大越好,Buffer如果太大,會導致申請Buffer的時間邊長,反而整體效率不高。可以採用檔案大小除以讀寫次數得到Buffer的大小。這個方法由兩個影響因子決定,一是Buffer size不能大於檔案大小;二是Buffer size根據檔案儲存所掛載的目錄的Block size來確定Buffer大小,而
- SQLite:資料庫在開啟後,先不要關閉,在應用程式退出時再關閉。
- SQLite:在資料庫中,應減少使用AUTOINCREMENT。AUTOINCREMENT可以保證主鍵的嚴格遞增,但是使用
AUTOINCREMENT
會增加INSERT
耗時1倍以上,所以使用AUTOINCREMENT
不可以任性,用在該用的敵方效果才佳。
SQLite官方:這個AUTOINCREMENT關鍵字會增加CPU,記憶體,磁碟空間和磁碟I/O的負擔,所以儘量不要用,除非必須。其實通常情況下都不是必需的。 - Bitmap解碼:
(1)解碼Bitmap
不要使用decodeFile
,因為在Android4.4以上系統效率不高。
(2)解碼Bitmap
使用decodeStream
,同時傳入的檔案流BufferedInputStream
。
(3)decodeResource
同樣存在效能問題,請用decodeResourceStream
。
解決方案:- 解碼Bitmap要使用
decodeStream
,不要說使用decodeFile
,同時傳給decodeStream
的檔案流是BufferedInputStream
。 decodeResource
同樣存在這個問題,建議使用decodeResourceStream
。
- 解碼Bitmap要使用
專項標準:磁碟
遵循標準 | 標準 | 優先順序 | 規則起源 |
---|---|---|---|
避免主執行緒I/O | 避免主執行緒操作檔案和資料庫。 | P0 | 50%以上的卡頓問題都是由主執行緒I/O引起的。 |
使用apply代替Sharepreference.commit | P1 | apply是非同步操作,commit是同步操作。 | |
提前初始化Sharepreference | P1 | 在多程序和舊版本的Android中,初始化過程的I/O讀/寫都是在主執行緒的。 | |
減少I/O讀寫量 | 減少使用select * | P1 | 減少從資料庫讀取的資料量,減少耗時。 |
利用快取減少重複讀寫 | P2 | 記憶體快取命中率極高,投入產出高。 | |
資料庫減少使用AUTOINCREMENT | P1 | 因為要多操作一個表,索引Insert耗時增加了2~4倍。 | |
使用合適的資料分頁 | P0 | sqlite讀寫磁碟是以page為單位的,在3.12.0之前,sqlite預設page size是1KB,從3.12.0開始,page size調整為4KB。 | |
頻繁查詢表使用索引 | P0 | 索引可以極大地較少讀磁碟的資料量,極大地提升效率。 | |
避免無效索引 | P0 | 無效索引的問題通常是嚴重的。除了觸發全表掃描,產生大量的冗餘的讀/寫之外,還降低了寫入效能。 | |
減少I/O操作次數 | 使用8KB Buffer讀/寫 | P0 | 可以減少2~3倍的耗時。 |
批量更新資料庫使用事務 | P0 | 啟用事務,根據業務規模,會大量減少I/O讀寫量和操作的次數,從而提升效率。 | |
ZIP壓縮大量小檔案的時候建議使用zipInputStream | P2 |
記憶體
記憶體檢測工具集
工具 | 問題 | 能力 |
---|---|---|
top/procrank | 記憶體佔用過大,記憶體洩露 | 發現 |
meminfo | Native記憶體洩露,是否存在Activity、ApplicationContext洩露、資料庫快取命中率低 | 發現+初步定位 |
MAT、Finder、JHAT | Java層的重複記憶體、不合理圖片解碼、記憶體洩露等等 | 發現 + 定位 |
libc_malloc_debug_leak.so | Native記憶體洩露(JNI層) | 發現 + 定位 |
LeakCanary | Activity記憶體洩露 | 自動發現 + 定位 |
StrictMode | Activity記憶體洩露 | 自動發現 + 初步定位 |
APT | 記憶體佔用過大,記憶體洩露 | 發現 |
GC Log from Logcat、GC Log生成圖表 | 人工觸發GC for Explicit而導致的卡頓,Heap記憶體不足觸發GC for Alloc而導致的卡頓 | 發現 + 初步定位 |
Systrace | GC導致的卡頓 | 發現 |
Allocation Tracer | 申請記憶體次數過多和過大、輔助定位GC Log發現的問題 | 發現 + 定位 |
chrome devtool | HS的記憶體問題 | 發現 + 定位 |
Android使用的是一個去掉了swap的linux核心(至少在Android4.4以前的版本都是這樣的),這樣就阻礙了Android上的應用程式使用Page out(應用程式使用的記憶體,對作業系統而言都是一張張的page,而對於老化的page,作業系統可以將它們從記憶體中置換到硬碟上,這種操作叫做page out),這一常規的記憶體操作。
Android框架對於程序記憶體的第二個管控特徵是,每個程序都有一個記憶體最高閥值(純淨的Native記憶體申請不算在內),一旦程序申請記憶體突破了這個閥值,將會產生異常,並退出執行時的記憶體空間。簡單的說,也就是Android為每個程序已經分好了一塊蛋糕,至於你吃或者不吃,是你的自己的事情了。但這是否意味著Android應用程式為了效率考慮,應該玩命的申請記憶體,使自己的記憶體沿著天花板滑行,這樣是否最健康呢?答案也不一定。
Android的第三個管控特徵是,程序都有可能被殺。在實體記憶體吃緊的時候(通常在使用meminfo檢視記憶體概況的PSS總值達到裝置實體記憶體80%的時候),Android框架就開始根據一套自由的LRU程序Cache列表來殺死程序,被殺死的程序在死前將會得到通知,用以儲存現場。而這部分被殺死的程序所騰出來的實體記憶體,就可以用於某些應用程式的記憶體申請需求。
Android記憶體框架下的各種管控特徵:
- 沒有Page out, 所以實體記憶體更加金貴。
- 每個程序都有一個記憶體上限,所以蛋糕是已經被分配好的。
- 所有的程序都有被殺的可能,所以要做好被殺準備。
專項標準:記憶體
遵循原則 | 標準 | 優先順序 | 規則起源 |
---|---|---|---|
避免記憶體洩露 | 避免Activity洩露 | P0 | 大部分嚴重的記憶體洩露都是Activity洩露,因為這意味著被引用的View、圖片等全部洩露。 |
減少常駐記憶體 | 儘量使用RGB565 | P1 | 手機QQ使用RGB565將節省部分圖片的記憶體,高達50%。 |
避免記憶體重複 | P1 | 手機QQ去掉頭像30%的重複快取,提升快取的命中率和流暢度。 | |
res/drawable裡的圖片,建議使用Drawable.createFromStream來載入 | P1 | 使用錯誤的資料夾,導致圖片被放大,最終APP使用的記憶體增加。 | |
將圖片放置到合適的資原始檔夾(hdpi、xxhdpi等) | P1 | 使用錯誤的資料夾,導致圖片被放大,最終APP使用的記憶體增加。 | |
減少GC | Bitmap儘量使用inBitmap | P1 | 可以減少GC,提升流暢度。 |
建議使用SpraseMap或者ArrayMap | P2 | ||
建議StringBuilder重用(如果由執行緒使用可配合ThreadLocal) | P1 | 手機QQ與QQ空間日誌改造,利用delete來替代new,給予合理的初始化長度,寫日誌效能提升多倍。 |
網路
工具集
工具 | 問題 | 能力 |
---|---|---|
Wireshark | 最專業的網路分析工具,全部網路效能問題的分析定位都可以檢視它。 | 發現+定位 |
fiddler | 主要針對HTTP,幫助發現HTTP眾多效能問題,還能模擬錯誤和演示的HTTP返回 | 發現+定位 |
tcpdump | 抓包工具,需要ROOT許可權 | 發現+定位 |
traceroute | 定位網路路由問題,包括就近接入、跨運營商問題 | 發現+定位 |
ARO | 無壓縮、重複下載、快取失效等,還有雅虎軍規中的其他問題 | 自動發現+定位 |
WebP/BPG | 圖片壓縮方案,前者基於webm的幀內壓縮,後者基於H.264的幀內壓縮 | 解決 |
SPDY/HTTP2.0/QUIC | 網路協議,利用FastTcpOpen減少握手次數,利用UDP更好的適應網路抖動 | 解決 |
WebPageTest.org | 如果要做Web應用的資料上報,建議參考之。它提供了LoadTime、StartRender、SpeedIndex,DOM Elements等耗時 | 發現+定位 |
tPackageCapture | 無ROOT轉包 | 定位 |
ATC | 最專業的弱網路模擬工具,除能模擬窄帶、延時、丟包、損壞包外,最關鍵的還有包亂序的情況 | 發現 |
工具庫
工具 | 說明 |
---|---|
AndroidGodEye是一個可以在PC瀏覽器中實時監控Android資料指標(比如效能指標,但是不侷限於效能)的工具,你可以通過wifi/usb連線手機和pc,通過pc瀏覽器實時監控手機效能。 系統分為三部分: 1. Core 核心部分,提供所有模組; 2. Debug Monitor部分,提供Debug階段開發者面板; 3. Toolbox 快速接入工具集,給開發者提供各種便捷接入的工具。 AndroidGodEye提供了多種監控模組,比如cpu、記憶體、卡頓、記憶體洩漏等等,並且提供了Debug階段的Monitor看板實時展示這 些資料。而且提供了api供開發者在release階段進行資料上報。 |