1. 程式人生 > >android系統性能優化(63)---Android APP 卡頓問題分析及解決方案

android系統性能優化(63)---Android APP 卡頓問題分析及解決方案

使用者對卡頓的感知, 主要來源於介面的重新整理. 而介面的效能主要是依賴於裝置的UI渲染效能. 如果我們的UI設計過於複雜, 或是實現不夠友好,計算繪製演算法不夠優化, 裝置又不給力, 介面就會像卡住了一樣, 給使用者卡頓的感覺.

如果你的應用介面出現卡頓不流暢的情況,不用懷疑,這很大原因是你沒有在16ms完成你的工作。沒錯,16ms要完成你的工作,再慢點,使用者就會感覺到卡頓,也許就會在螢幕對面開始吐槽你的APP,然後狠心把你辛辛苦苦開發出來的APP給解除安裝掉,打住,跑偏了!

1、16ms原則

Android 在不同的版本都會優化“UI的流暢性”問題,但是直到在android 4.1版本中做了有效的優化,這就是Project Butter。 
Project Butter 加入了三個核心元素: VSYNC、Triple Buffer 和 Choreographer。其中,VSYNC

 是理解Project Buffer的核心。

VSYNC:產生一箇中斷訊號 
Triple Buffer:當雙 Buffer 不夠使用時,該系統可分配第三塊 Buffer 
Choreographer:這個用來接受一個 VSYNC 訊號來統一協調UI更新

接下來我們就逐個去解析這3個核心元素: 
在瞭解VSYNC之前,我們首先來了解一下我們在 xml 寫的一個佈局是如何載入到Acitivty/Fragment中並最終 display 呢?,我相信這個過程大部分程式猿也並不是很關心,因為 Android 底層都為為我們搞定這一部分的處理。但是如果要了解16ms原則,我們簡單瞭解下這個過程是非常有必要的。先看我簡單畫的一個圖:

這裡寫圖片描述

從上面的圖可以看出,CPU 會先把 Layout 中的 UI 元件計算成 polygons(多邊形)和 textures(紋理),然後經過 OpenGL ES 處理(這個處理過程非常複雜,感興趣的童鞋可以繼續耕耘)。OpenGL ES處理完後再交給 GPU 進行柵格化渲染,渲染後 GPU 再將資料傳送給螢幕,由螢幕進行繪製顯示。

Activity 的介面之所以可以被繪製到螢幕上其中有一個很重要的過程就是 柵格化(Resterization),柵格化簡單來說就是將向量圖轉化為機器可以識別的點陣圖的一個過程。其中很複雜也比較很耗時,GPU 就是用來加快柵格化的速度。瞭解了這個過程後,我們在來理解 VSYNC

1、1 關於VSYNC

  • VSYNC 這個概念出來很久了,Vertical Synchronization,就是所謂的“垂直同步”。在 Android 中也沿用了這個概念,我們也可以把它理解為“幀同步”。這個用來幹嘛的呢,就是為了保證 CPU、GPU 生成幀的速度和 Display 重新整理的速度保持一致。

  • Android 系統每 16ms(更準確的是大概16.6ms) 就會發出一次 VSYNC訊號觸發 UI 渲染更新。大約螢幕一秒重新整理60次,也就是說要求 CPU 和 GPU 每秒要有處理 60 幀的能力,一幀花費的時間在 16ms 內。

  • 這個方案的原理主要是通過 Choreographer 類設定它的 FrameCallback 函式,當每一幀被渲染時會觸發回撥 FrameCallback, FrameCallback 回撥 void doFrame (long frameTimeNanos) 函式。一次介面渲染會回撥 doFrame 方法,如果兩次 doFrame 之間的間隔大於 16.6ms 說明發生了卡頓。

如果你平時注意卡頓的日誌資訊,那麼下面這個段log就不會陌生了

if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
     Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                           + "The application may be doing too much work on its main thread.");

SKIPPED_FRAME_WARNING_LIMIT 的預設值是 30,也就說當我們的程式卡頓大於 30 時會列印這條 log 資訊

那麼在 Android系統中,是如何利用 VSYNC 工作的呢?

一句話總結:在 VSYNC 開始發出訊號時,CPU和GPU已經就開始準備下一幀的資料了,趕在下個 VSYNC 訊號到來時,GPU 渲染完成,及時傳送資料給螢幕,Display 繪製顯示完成。不出什麼意外的話,每一幀都會這麼井然有序進行著,在這種理想狀態下,使用者就會體驗到如絲般順滑的感覺了。當然你也不會看到這篇部落格了,囧!

上面總結的一句話,如果用更專業的術語來說就是一個名詞,雙緩衝機制

1、2 雙緩衝機制

雙緩衝技術一直貫穿整個 Android 系統。因為實際上幀的資料就是儲存在兩個 Buffer 緩衝區中,A 緩衝用來顯示當前幀,那麼 B 緩衝就用來快取下一幀的資料,同理,B顯示時,A就用來緩衝!這樣就可以做到一邊顯示一邊處理下一幀的資料。

這樣看起來貌似沒什麼問題,一切都是我們的掌控中。但是,由於某些原因,比如我們應用程式碼上邏輯處理過於負責或者過於複雜的佈局,過度繪製(Overdraw),UI執行緒的複雜運算,頻繁的GC等,導致下一幀繪製的時間超過了16ms,那麼問題就來了,這時候使用者就不爽了,因為使用者很明顯感知到了卡頓的出現,也就是所謂的丟幀情況。如下圖所示:

這裡寫圖片描述

ok,下面我們來認真分析一下為什麼會出現丟幀的情況:

1、當 Display 顯示第 0 幀資料時,此時 CPU 和 GPU 已經開始渲染第 1 幀畫面,並將資料快取在緩衝 B 中。但是由於某些原因,就好像上面說的,導致系統處理該幀資料耗時過長或者未能及時處理該幀資料。

2、當 VSYNC 訊號來時,Display 向 B 緩衝要資料,這時候 B 就藍瘦香菇了,因為緩衝 B 的資料還沒準備好,B緩衝區這時候是被鎖定的,Display 表示你沒準備好,我咋辦呢,無奈,只能繼續顯示之前緩衝 A 的那一幀,此時緩衝 A 的資料也不能被清空和交換資料。這種情況就是所謂的“丟幀”,也被稱作“廢幀”;當第 1 幀資料(即緩衝 B 資料)準備完成後,它並不會馬上被顯示,而是要等待下一個 VSYNC,Display 重新整理後,這時使用者才看到畫面的更新。

3、當某一處丟幀後,大概率會影響後面的繪製也出現丟幀,最走給使用者感覺就是卡頓了。最嚴重的直接造成ANR。

2、Triple Buffer

既然丟幀的情況不可避免,Android 團隊從未放棄對這塊的優化處理,於是便出現了Triple Buffer(三緩衝機制)

在三倍緩衝機制中,系統這個時候會建立一個緩衝 C,用來緩衝下一幀的資料。也就是說在顯示完緩衝B中那一幀後,下一幀就是顯示緩衝 C 中的了。這樣雖然還是不能避免會出現卡頓的情況,但是 Android 系統還是盡力去彌補這種缺陷,最終儘可能給用平滑的動效體驗。

3、卡頓處理

下面我們就以下幾種情況導致卡頓問題進行分析處理。

3.1 過於複雜的佈局

介面效能取決於 UI 渲染效能. 我們可以理解為 UI 渲染的整個過程是由 CPU 和 GPU 兩個部分協同完成的。

其中, CPU 負責UI佈局元素的 Measure, Layout, Draw 等相關運算執行. GPU 負責柵格化(rasterization), 將UI元素繪製到螢幕上。

如果我們的 UI 佈局層次太深, 或是自定義控制元件的 onDraw 中有複雜運算, CPU 的相關運算就可能大於16ms, 導致卡頓。

解決方案: 
我們需要藉助 Hierarchy Viewer 這個工具來幫我們分析佈局了. Hierarchy Viewer 不僅可以以圖形化樹狀結構的形式展示出UI層級, 還對每個節點給出了三個小圓點, 以指示該元素 Measure, Layout, Draw 的耗時及效能。

2.2 過度繪製( Overdraw )

Overdraw: 用來描述一個畫素在螢幕上多少次被重繪在一幀上.

通俗的說: 理想情況下, 每屏每幀上, 每個畫素點應該只被繪製一次, 如果有多次繪製, 就是 Overdraw, 過度繪製了。 常見的就是:繪製了多重背景或者繪製了不可見的UI元素.

解決方案: 
Android系統提供了視覺化的方案來讓我們很方便的檢視overdraw的現象: 
在”系統設定”–>”開發者選項”–>”除錯GPU過度繪製”中開啟除錯: 
此時介面可能會有五種顏色標識:

overdraw indicator

  • 原色: 沒有overdraw
  • 藍色: 1次overdraw
  • 綠色: 2次overdraw
  • 粉色: 3次overdraw
  • 紅色: 4次及4次以上的overdraw

一般來說, 藍色是可接受的, 是效能優的.

2.3 UI 執行緒的複雜運算

UI執行緒的複雜運算會造成UI無響應, 當然更多的是造成UI響應停滯, 卡頓。產生ANR已經是卡頓的極致了。

解決方案: 
關於運算阻塞導致的卡頓的分析, 可以使用 Traceview 這個工具。

2.4 頻繁的 GC

上面說的都是處理上的CPU, GPU 相關的. 實際上記憶體原因也可能會造成應用不流暢, 卡頓的。

為什麼說頻繁的 GC 會導致卡頓呢? 
簡而言之, 就是執行 GC 操作的時候,任何執行緒的任何操作都會需要暫停,等待 GC 操作完成之後,其他操作才能夠繼續執行, 故而如果程式頻繁 GC, 自然會導致介面卡頓。

導致頻繁GC有兩個原因:

  • 記憶體抖動(Memory Churn), 即大量的物件被建立又在短時間內馬上被釋放。
  • 瞬間產生大量的物件會嚴重佔用 Young Generation 的記憶體區域, 當達到閥值, 剩餘空間不夠的時候, 也會觸發 GC。即使每次分配的物件需要佔用很少的記憶體,但是他們疊加在一起會增加 Heap 的壓力, 從而觸發更多的 GC。

解決方案: 
一般來說瞬間大量產生物件一般是因為我們在程式碼的迴圈中 new 物件, 或是在 onDraw 中建立物件等。 
還是是儘量不要在迴圈中大量的使用區域性變數。所以說這些地方是我們尤其需要注意的。

相關推薦

android系統性優化63---Android APP 問題分析解決方案

使用者對卡頓的感知, 主要來源於介面的重新整理. 而介面的效能主要是依賴於裝置的UI渲染效能. 如果我們的UI設計過於複雜, 或是實現不夠友好,計算繪製演算法不夠優化, 裝置又不給力, 介面就會像卡住了一樣, 給使用者卡頓的感覺.如果你的應用介面出現卡頓不流暢的情況,不用懷疑,這很大原因是你沒有在16ms完成

Android 系統性優化16--Android 系統性優化第4季

1)Cachematters for networking想要使得Android系統上的網路訪問操作更加的高效就必須做好網路資料的快取。這是提高網路訪問效能最基礎的步驟之一。從手機的快取中直接讀取資料肯定比從網路上獲取資料要更加的便捷高效,特別是對於那些會被頻繁訪問到的資料,

Android 系統性優化34---Android UI 效能優化

Android官網 Slow rendering;個人覺得非常有價值,比如指出 物件分配、垃圾回收(GC)、執行緒排程以及Binder呼叫 是Android系統中常見的卡頓原因,更重要的是給出了定位和解決這些問題的方案;而非簡單地告訴你避免物件分配,減少佈局層級,減少過度

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

磁碟檔案讀寫:每次開啟、關閉或者讀寫檔案,作業系統都需要經過從使用者態轉換為核心態的切換,這種狀態的切換本身是很消耗效能的,所以為了提高檔案的讀寫效率,就需要儘量減少使用者態和核心態的切換。使用快取可以避免重複讀寫,對於需要多次訪問的資料,在第一次取出資料的時候,將資料放在快

Android 系統性優化30---Android效能全面分析優化方案研究

5.1、渲染問題先來看看造成應用UI卡頓的常見原因都有哪些?1、人為在UI執行緒中做輕微耗時操作,導致UI執行緒卡頓;2、佈局Layout過於複雜,無法在16ms內完成渲染;3、同一時間動畫執行的次數過多,導致CPU或GPU負載過重;4、View過度繪製,導致某些畫素在同一幀時間內被繪製多次,從而使CPU或G

Android 系統性優化11---UC效能優化方案

       一、效能優化六項指標:              效能、記憶體、穩定性、流量、電量、安裝包大小;       二、背景 ---- Android程式卡頓產生原因:              1、Android系統低效              --渲染執行緒、同步介面、廣播機制         

Android 系統性優化36---顯示效能指標

    從 Android 誕生的那一刻起,流暢度就為眾人所關注。一時之間,似乎所有人都在討論 Android 和 iOS 誰的流暢度更好。但是,毫不誇張的說,流暢度絕對是 Android 眾多效能維度中最為奇葩的一個。因為,為了刻畫這一效能維度,業界設計了各式各樣的指標來對

Android 系統性優化52---移動端效能監控方案Hertz

效能問題是造成App使用者流失的罪魁禍首之一。App的效能問題包括崩潰、網路請求錯誤或超時、響應速度慢、列表滾動卡頓、流量大、耗電等等。而導致App效能低下的原因有很多,除去裝置硬體和軟體的外部因素,其中大部分是開發者錯誤地使用執行緒、鎖、系統函式、程式設計正規化、資料結構等導致的。即便是最有經驗的程式設計師

Android系統性優化64---build.設定

1. 強制把Home程式駐入記憶體.引數:ro.HOME_APP_ADJ=12.提高 JPG 質量為 100%引數:ro.media.enc.jpeg.quality=1003. VM 虛擬堆大小; 提高 RAM引數:dalvik.vm.heapsize=48m4. 使用 GPU 渲染UI引數:debug.s

Android系統性優化44---全面&詳細的記憶體優化指南

前言在 Android開發中,效能優化策略十分重要本文主要講解效能優化中的記憶體優化,希望你們會喜歡目錄1. 定義優化處理 應用程式的記憶體使用、空間佔用2. 作用避免因不正確使用記憶體 & 缺乏管理,從而出現 記憶體洩露(ML)、記憶體溢位(OOM)、記憶體空間佔用

Android 介面滑動分析解決方案

導致Android介面滑動卡頓主要有兩個原因: 1.UI執行緒(main)有耗時操作 2.檢視渲染時間過長,導致卡頓 目前只講第1點,第二點相對比較複雜待以後慢慢研究。 眾所周知,介面的流暢度主要依賴FPS這個值,這個值是通過(1s/渲染1幀所花費的時間)計算所得,FPS值越大視訊越流暢,所以就需要渲染1幀

React-Native學習之路TabNavigator隱藏問題的分析解決

首先說明一下我是用的TabNavigator+StackNavigator來寫的頁面跳轉。 我們先分析一下為什麼在每個Tab的Item裡面實現跳轉,跳轉頁面還是會有底部的TabNvigator 先看下我出問題的專案結構,首先,我們可以看到我給這個Tab的Item指定的

Android繪制優化繪制性分析

pro -i tco public 繼續 但是 們的 sched mda 前言 一個優秀的應用不僅僅是要有吸引人的功能和交互,同時在性能上也有很高的要求。運行Android系統的手機,雖然配置在不斷的提升,但仍舊無法和PC相比,無法做到PC那樣擁有超大的內存以及高性能的CP

Android內存優化DVM和ART原理初探

java虛擬機 劃分 cimage beef 靜態 由於 jar blank 查找 要學習Android的內存優化,首先要了解Java虛擬機,此前我用了多篇文章來介紹Java虛擬機的知識,就是為了這個系列做鋪墊。在Android開發中我們接觸的是與Java虛擬機類似的Dal

Android內存優化Dalvik虛擬機和ART虛擬機對比

參考 -a 會有 font google 都是 http -s 轉換成 1.概述  Android4.4以上開始使用ART虛擬機,在此之前我們一直使用的Dalvik虛擬機,那麽為什麽Google突然換了Android運行的虛擬機呢?答案只有一個:ART虛擬機更優秀。 2.D

記憶體優化Android物件池使用

文章目錄 概述 Android Object Pools Pools原始碼解析: Pools結合Builder模式使用案例: 使用總結和注意事項 概述

Android 系統性優化(14)---Android效能優化典範

1)Battery Drain and Networking對於手機程式,網路操作相對來說是比較耗電的行為。優化網路操作能夠顯著節約電量的消耗。在效能優化第1季裡面有提到過,手機硬體的各個模組的耗電量是不一樣的,其中移動蜂窩模組對電量消耗是比較大的,另外蜂窩模組在不同工作強度

演算法移植優化android gpuimage使用

1、在androidMainfest.xml中加入: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STO

Mysql數據庫性優化

效率 dir sort variables 緩存 模型 mysql5.6 包含 dpt 參考 http://www.jb51.net/article/82254.htm 今天,數據庫的操作越來越成為整個應用的性能瓶頸了,這點對於Web應用尤其明顯。關於數據庫的性能,這並不只

Android優化系列---管理你的app內存

分頁 分隔 條件 format 們的 靜態常量 rim 發生 測試 文章出處:http://developer.android.com/training/articles/memory.html#YourApp Random-access memory(RAM)在任何軟