1. 程式人生 > >Android 系統性能優化(28)---Android 效能優化工具集合

Android 系統性能優化(28)---Android 效能優化工具集合

磁碟

  1. 檔案讀寫:每次開啟、關閉或者讀寫檔案,作業系統都需要經過從使用者態轉換為核心態的切換,這種狀態的切換本身是很消耗效能的,所以為了提高檔案的讀寫效率,就需要儘量減少使用者態和核心態的切換。使用快取可以避免重複讀寫,對於需要多次訪問的資料,在第一次取出資料的時候,將資料放在快取中,下次再訪問的時候,就可以從快取中取出來。
  2. Android手機裡面的libsqlite.so呼叫系統的pread64pwrite64函式進行I/O操作
  3. 序列化ObjectOutputStream序列化磁碟的時候,會把記憶體中的每個物件儲存到磁碟,在儲存物件的時候,每一個數據成員會帶來一次I/O操作。因此,在使用ObjectOutputStream

    的時候,在ObjectOutputStream上面再封裝一個輸出流ByteArrayOuputStream先將物件序列化後的資訊寫到快取區中,然後再一次性地寫到磁碟上。

    序列化磁碟讀寫方式優化前優化後
    序列化寫磁碟ObjectOutputStreamBufferedOutputStream + ObjectOutputStream
    ByteArrayOutputStream + ObjectOutputStream
    序列化讀磁碟ObjectInputStreamBufferedInputStream + ObjectInputStream
    ByteArrayInputStream + ObjectInputStream
    序列化磁碟讀寫方式優化前後I/O次數耗時(ms)
    序列化寫磁碟優化前499162.8
    優化後187.3
    序列化讀磁碟優化前719171.8
    優化後1109.9
  4. Buffer緩衝區大小:在讀/寫時使用緩衝區可以減少讀寫次數,從而減少了切換核心態的次數,提高讀/寫效率,根據實際經驗,這裡推薦使用的Buffer大小為8KB,這和Java預設的Buffer大小一致,Buffer大小至少應為4KB。當然,Buffer也不是越大越好,Buffer如果太大,會導致申請Buffer的時間邊長,反而整體效率不高。可以採用檔案大小除以讀寫次數得到Buffer的大小。這個方法由兩個影響因子決定,一是Buffer size不能大於檔案大小;二是Buffer size根據檔案儲存所掛載的目錄的Block size來確定Buffer大小,而
    資料庫的pagesize,就是這樣確定的。
  5. SQLite:資料庫在開啟後,先不要關閉,在應用程式退出時再關閉。
  6. SQLite:在資料庫中,應減少使用AUTOINCREMENT。AUTOINCREMENT可以保證主鍵的嚴格遞增,但是使用AUTOINCREMENT會增加INSERT耗時1倍以上,所以使用AUTOINCREMENT不可以任性,用在該用的敵方效果才佳。

    SQLite官方:這個AUTOINCREMENT關鍵字會增加CPU,記憶體,磁碟空間和磁碟I/O的負擔,所以儘量不要用,除非必須。其實通常情況下都不是必需的。

  7. Bitmap解碼:
    (1)解碼Bitmap不要使用decodeFile,因為在Android4.4以上系統效率不高。
    (2)解碼Bitmap使用decodeStream,同時傳入的檔案流BufferedInputStream

    (3)decodeResource同樣存在效能問題,請用decodeResourceStream
    解決方案: 
    1. 解碼Bitmap要使用decodeStream,不要說使用decodeFile,同時傳給decodeStream的檔案流是BufferedInputStream
    2. decodeResource同樣存在這個問題,建議使用decodeResourceStream

專項標準:磁碟

遵循標準標準優先順序規則起源
避免主執行緒I/O避免主執行緒操作檔案和資料庫。P050%以上的卡頓問題都是由主執行緒I/O引起的。
使用apply代替Sharepreference.commitP1apply是非同步操作,commit是同步操作。
提前初始化SharepreferenceP1在多程序和舊版本的Android中,初始化過程的I/O讀/寫都是在主執行緒的。
減少I/O讀寫量減少使用select *P1減少從資料庫讀取的資料量,減少耗時。
利用快取減少重複讀寫P2記憶體快取命中率極高,投入產出高。
資料庫減少使用AUTOINCREMENTP1因為要多操作一個表,索引Insert耗時增加了2~4倍。
使用合適的資料分頁P0sqlite讀寫磁碟是以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壓縮大量小檔案的時候建議使用zipInputStreamP2

記憶體

記憶體檢測工具集

工具問題能力
top/procrank記憶體佔用過大,記憶體洩露發現
meminfoNative記憶體洩露,是否存在Activity、ApplicationContext洩露、資料庫快取命中率低發現+初步定位
MAT、Finder、JHATJava層的重複記憶體、不合理圖片解碼、記憶體洩露等等發現 + 定位
libc_malloc_debug_leak.soNative記憶體洩露(JNI層)發現 + 定位
LeakCanaryActivity記憶體洩露自動發現 + 定位
StrictModeActivity記憶體洩露自動發現 + 初步定位
APT記憶體佔用過大,記憶體洩露發現
GC Log from Logcat、GC Log生成圖表人工觸發GC for Explicit而導致的卡頓,Heap記憶體不足觸發GC for Alloc而導致的卡頓發現 + 初步定位
SystraceGC導致的卡頓發現
Allocation Tracer申請記憶體次數過多和過大、輔助定位GC Log發現的問題發現 + 定位
chrome devtoolHS的記憶體問題發現 + 定位

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、圖片等全部洩露。
減少常駐記憶體儘量使用RGB565P1手機QQ使用RGB565將節省部分圖片的記憶體,高達50%。
避免記憶體重複P1手機QQ去掉頭像30%的重複快取,提升快取的命中率和流暢度。
res/drawable裡的圖片,建議使用Drawable.createFromStream來載入P1使用錯誤的資料夾,導致圖片被放大,最終APP使用的記憶體增加。
將圖片放置到合適的資原始檔夾(hdpi、xxhdpi等)P1使用錯誤的資料夾,導致圖片被放大,最終APP使用的記憶體增加。
減少GCBitmap儘量使用inBitmapP1可以減少GC,提升流暢度。
建議使用SpraseMap或者ArrayMapP2
建議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階段進行資料上報。