Android應用卡頓優化之路(一)-TraceView

1 通過TraceView發現程序代碼可優化的點

1.1 TraceView簡介

TraceView 簡介
TraceView 是 Android 平臺特有的數據采集和分析工具,它主要用于分析 Android 中應用程序的 hotspot。TraceView 本身只是一個數據分析工具,而數據的采集則需要使用 Android SDK 中的 Debug 類或者利用 DDMS 工具。二者的用法如下:
開發者在一些關鍵代碼段開始前調用 Android SDK 中 Debug 類的 startMethodTracing 函數,并在關鍵代碼段結束前調用 stopMethodTracing 函數。這兩個函數運行過程中將采集運行時間內該應用所有線程(注意,只能是 Java 線程)的函數執行情況,并將采集數據保存到 /mnt/sdcard/ 下的一個文件中。開發者然后需要利用 SDK 中的 TraceView 工具來分析這些數據。

1.2 TraceView使用

借助 Android SDK 中的 DDMS 工具。DDMS 可采集系統中某個正在運行的進程的函數調用信息。對開發者而言,此方法適用于沒有目標應用源代碼的情況。
在Android Studio --> Tools --> Android --> Android Device Monitor打開DDMS

DDMS 中 TraceView 使用示意圖如下,調試人員可以通過選擇 Devices 中的應用后點擊
按鈕 Start Method Profiling(開啟方法分析)和點擊
Stop Method Profiling(停止方法分析)

點擊開始錄制后,我們就可以開始操作App,想測試哪里就點哪里(步步高打火機,哪里不會點哪里)。
錄制完成后點擊同一個按鈕結束,就可以看到以下的TraceView界面。

TraceView概覽

TraceView 界面比較復雜,其 UI 劃分為上下兩個面板,即 Timeline Panel(時間線面板)和 Profile Panel(分析面板)。上圖中的上半部分為 Timeline Panel(時間線面板),Timeline Panel 又可細分為左右兩個 Pane:
左邊 Pane 顯示的是測試數據中所采集的線程信息。由圖可知,本次測試數據采集了 main 線程,傳感器線程和其它系統輔助線程的信息。
右邊 Pane 所示為時間線,時間線上是每個線程測試時間段內所涉及的函數調用信息。這些信息包括函數名、函數執行時間等。由圖可知,Thread-1412 線程對應行的的內容非常豐富,而其他線程在這段時間內干得工作則要少得多。
另外,開發者可以在時間線 Pane 中移動時間線縱軸。縱軸上邊將顯示當前時間點中某線程正在執行的函數信息。
上圖中的下半部分為 Profile Panel(分析面板),Profile Panel 是 TraceView 的核心界面,其內涵非常豐富。它主要展示了某個線程(先在 Timeline Panel 中選擇線程)中各個函數調用的情況,包括 CPU 使用時間、調用次數等信息。而這些信息正是查找 hotspot 的關鍵依據。

1.3 然后我們根據Incl Cpu Time進行降序排列,看看那些方法調用的時間最長,如下圖所示:

根據Incl Cpu Time降序排列

先說說標題欄上的各個指標是什么意思:

指標含義

結合Excl Real Time查看方法自身耗時,同時注意CPU占用率,CPU占用率達到100%的基本上都很可疑了,需要看看是否有死循環調用。
結合方法的調用次數查看,方法調用次數特別多的也可以看看有什么可以優化的地方。

1.4 點開調用占用CPU時間最長的第一個方法,Thread.run()方法,看看是哪里調用了

image.png

看起來這個方法非常可疑,到代碼里看看

FlowerCanvasLayout里面的mThread變量的run方法

FlowerCanvasLayout里面的mThread變量的run方法果然干了件坑爹的事情,我們都知道代碼是要在CPU里跑的(這特么不是廢話嗎?),很多剛開始開發Android的同學覺得,雖然Android主線程不能隨便進行耗時操作,同理也不能死循環,那我在子線程里死循環就可以啦,但是這樣是有問題的,在子線程中進行死循環操作,雖然CPU會剝奪子線程的時間片,但是子線程里會搶占主線程的時間片,就好像雖然一個子線程能搶的時間片不多,但是如果有多個子線程呢?子線程里還有死循環的代碼,這是萬萬不可的,因此這里我們需要在子線程中單次循環進行線程掛起,在合適的時候喚醒此線程避免一直進行死循環等待。

1.5 JSON在主線程解析

繼續通過TraceView查找調用特別耗時的方法,看到一個,圖片可能不好看清,主要看看方法調用時間,

查看另外一個特別耗時的方法,發現是解析JSON的操作

查看代碼,發現在SocketActivity中調用了SocketMessageHelper.handleSocketMessage,看看這個方法里干了什么。

在主線程里使用解析JSON!

這個JSON是服務器通過Socket分發的各種事件,非常長,連Logcat都無法完成打印出來,可想而知在主線程里解析這么長的JSON字符串會導致多么的卡頓。

解決辦法:把JSON解析移動到工作線程中完成,解析完成后分發給主線程

1.6 更多的優化例子持續更新...

主要的是要學會使用TraceView找出App中可以優化的點,每個例子只是一種方法

1.7 寫代碼過程中避免主線程卡頓的注意事項:

1)不要大量使用new Thread()的方式初始化子線程,這樣會導致大量的線程創建活動,線程創建是很耗時的,而且還帶有內存占用(好像是64KB?),盡量使用線程池的方式復用線程。

2)不要創建太多子線程,太多子線程會搶占主線程時間片,導致UI卡頓,使用緩存線程池。

3)創建子線程時記得設置優先級為較低優先級
線程池框架:

private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "TaskExecutor #" + mCount.getAndIncrement());
            t.setPriority(Thread.MIN_PRIORITY);
            return t;
        }
    };

HandlerThread:

mHandlerThread = new HandlerThread(threadName, android.os.Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();

4)不要讓主線程和工作線程競爭同一個鎖,容易讓主線程卡頓等待,導致ANR,盡量讓主線程不需要獲取鎖,需要獲取鎖的方法盡量在子線程調用。

5)解析JSON等耗時操作不要在主線程執行

6)不要讓工作線程進行死循環,這樣會大大增加CPU使用率,增加設備耗電并且降低主線程的效率。

7)減少SharePreferences打開關閉次數,盡量合并寫入,減少磁盤讀取寫入次數,使用apply()代替commit(),這個雖然是簡單的優化,但是能大大減少主線程讀寫文件帶來的卡頓(SharePreference是XML文件,使用commit同步寫入的話在主線程讀寫磁盤會有性能損耗,使用apply異步寫入代替,很多開發人員不重視這一點)

8)避免在主線程操作文件和數據庫

9)使用適當大小的Buffer讀寫文件 ,過小的Buffer會導致多次讀寫磁盤,例如一個1M的文件,你使用1K的Buffer就需要讀十次,10M的文件呢?

//buffer的大小根據業務文件平均大小選擇
FileInputStream in = ...
byte[] buffer = new byte[8196];
while (len = in. read(buffer,0,8196))  != -1) {
    
}

10)除非必要,否則盡量不要使用索引(AUTOINCREMENT),使用索引需要維護多一張索引表,寫入時都需要進行多次寫入磁盤,會影響寫入效率,頻繁查詢的表才適合使用索引,頻繁寫入少查詢的表不適合使用索引。

SQLite創建一個叫sqlite_sequence的內部表來記錄該表使用的最大行號。如果指定使用AUTOINCREMENT來創建表,則sqlite_sequence也隨之創建。UPDATE、INSERT、DELETE語句可能會修改sqlite_sequence的內容。因為維護sqlite_sequence表帶來的額外開銷會導致INSERT的效率降低。

11)避免使用低效率的API,如上面的JSON解析方法,原來的代碼直接使用了Java自帶的JSON API解析,這個庫的解析效率較低,替換使用GSON解析,并且解析方法放到工作線程中。

12)某些特別消耗計算能力的方法,可以通過RenderThread放到GPU中調用。

2 參考

Android 編程下的 TraceView 簡介及其案例實戰
Android移動性能實戰

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,714評論 25 708
  • 一、關于App性能優化 1. 性能優化分類 Google官方給出的性能優化教程,主要分為以下幾類:1)布局與UI渲...
    cszhangchao閱讀 1,923評論 0 6
  • source: ICCV09authors: Daniel Glasner Shai Bagon Michal ...
    OWNSTYLEDU_大鵬閱讀 2,893評論 1 1
  • 時光的流逝,早已不再是最初的我們。 誰敢想到這烏煙瘴氣,滿是塵埃的天空,最初竟是天空澄碧,纖云不染,和風送暖的景象...
    Pressure_b82c閱讀 251評論 0 0
  • 記憶 的確沒有什么能跟記憶并駕齊驅的稱為重要 深處當下的每一刻 我們都會感到周遭的無聊乏味 或者碌碌無為 或者燈紅...
    蔓草島嶼閱讀 177評論 0 0