Android效能最佳化典範

來源:互聯網
上載者:User

標籤:

    Android效能最佳化典範
    我們可以通過前面介紹的MonitorGPURendering來查看渲染的表現效能如何,另外也可以通過開發人員選項裡面的ShowGPUviewupdates來查看視圖更新的操作,最後我們還可以通過HierarchyViewer這個工具來查看布局,使得布局盡量扁平化,移除非必需的UI組件,這些操作能夠減少Measure,Layout的計算時間。
    8)Overdraw,Cliprect,QuickReject
    引起效能問題的一個很重要的方面是因為過多複雜的繪製操作。我們可以通過工具來檢測並修複標準UI組件的Overdraw問題,但是針對高度自訂的UI組件則顯得有些力不從心。
    有一個竅門是我們可以通過執行幾個APIs方法來顯著提升繪製操作的效能。前面有提到過,非可見的UI組件進行繪製更新會導致Overdraw。例如NavDrawer從前置可見的Activity滑出之後,如果還繼續繪製那些在NavDrawer裡面不可見的UI組件,這就導致了Overdraw。為瞭解決這個問題,Android系統會通過避免繪製那些完全不可見的組件來盡量減少Overdraw。那些NavDrawer裡面不可見的View就不會被執行浪費資源。
    但是不幸的是,對於那些過於複雜的自訂的View(重寫了onDraw方法),Android系統無法檢測具體在onDraw裡面會執行什麼操作,系統無法監控並自動最佳化,也就無法避免Overdraw了。但是我們可以通過canvas.clipRect()來協助系統識別那些可見的地區。這個方法可以指定一塊矩形地區,只有在這個地區內才會被繪製,其他的地區會被忽視。這個API可以很好的協助那些有多組重疊組件的自訂View來控制顯示的地區。同時clipRect方法還可以協助節約CPU與GPU資源,在clipRect地區之外的繪製指令都不會被執行,那些部分內容在矩形地區內的組件,仍然會得到繪製。
    除了clipRect方法之外,我們還可以使用canvas.quickreject()來判斷是否沒和某個矩形相交,從而跳過那些非矩形地區內的繪製操作。做了那些最佳化之後,我們可以通過上面介紹的ShowGPUOverdraw來查看效果。
    9)MemoryChurnandperformance
    雖然Android有自動管理記憶體的機制,但是對記憶體的不恰當使用仍然容易引起嚴重的效能問題。在同一幀裡面建立過多的對象是件需要特別引起注意的事情。
    Android系統裡面有一個GenerationalHeapMemory的模型,系統會根據記憶體中不同的記憶體資料類型分別執行不同的GC操作。例如,最近剛分配的對象會放在YoungGeneration地區,這個地區的對象通常都是會快速被建立並且很快被銷毀回收的,同時這個地區的GC操作速度也是比OldGeneration地區的GC操作速度更快的。
    除了速度差異之外,執行GC操作的時候,任何線程的任何操作都會需要暫停,等待GC操作完成之後,其他動作才能夠繼續運行。
    通常來說,單個的GC並不會佔用太多時間,但是大量不停的GC操作則會顯著佔用幀間隔時間(16ms)。如果在幀間隔時間裡面做了過多的GC操作,那麼自然其他類似計算,渲染等操作的可用時間就變得少了。
    導致GC頻繁執行有兩個原因:
    MemoryChurn記憶體抖動,記憶體抖動是因為大量的對象被建立又在短時間內馬上被釋放。
    瞬間產生大量的對象會嚴重佔用YoungGeneration的記憶體地區,當達到閥值,剩餘空間不夠的時候,也會觸發GC。即使每次分配的對象佔用了很少的記憶體,但是他們疊加在一起會增加Heap的壓力,從而觸發更多其他類型的GC。這個操作有可能會影響到幀率,並使得使用者感知到效能問題。
    解決上面的問題有簡潔直觀方法,如果你在MemoryMonitor裡面查看到短時間發生了多次記憶體的漲跌,這意味著很有可能發生了記憶體抖動。
    同時我們還可以通過AllocationTracker來查看在短時間內,同一個棧中不斷進出的相同對象。這是記憶體抖動的典型訊號之一。
    當你大致定位問題之後,接下去的問題修複也就顯得相對直接簡單了。例如,你需要避免在for迴圈裡面指派至佔用記憶體,需要嘗試把對象的建立移到迴圈體之外,自訂View中的onDraw方法也需要引起注意,每次螢幕發生繪製以及動畫執行過程中,onDraw方法都會被調用到,避免在onDraw方法裡面執行複雜的操作,避免建立對象。對於那些無法避免需要建立對象的情況,我們可以考慮對象池模型,通過對象池來解決頻繁建立與銷毀的問題,但是這裡需要注意結束使用之後,需要手動釋放對象池中的對象。
    10)GarbageCollectioninAndroid
    JVM的回收機制給開發人員帶來很大的好處,不用時刻處理對象的分配與回收,可以更加專註於更加進階的代碼實現。相比起Java,C與C++等語言具備更高的執行效率,他們需要開發人員自己關注對象的分配與回收,但是在一個龐大的系統當中,還是免不了經常發生部分對象忘記回收的情況,這就是記憶體流失。
    原始JVM中的GC機制在Android中得到了很大程度上的最佳化。Android裡面是一個三級Generation的記憶體模型,最近分配的對象會存放在YoungGeneration地區,當這個對象在這個地區停留的時間達到一定程度,它會被移動到OldGeneration,最後到PermanentGeneration地區。
    每一個層級的記憶體地區都有固定的大小,此後不斷有新的對象被分配到此地區,當這些對象總的大小快達到這一層級記憶體地區的閥值時,會觸發GC的操作,以便騰出空間來存放其他新的對象。
    前面提到過每次GC發生的時候,所有的線程都是暫停狀態的。GC所佔用的時間和它是哪一個Generation也有關係,YoungGeneration的每次GC操作時間是最短的,OldGeneration其次,PermanentGeneration最長。執行時間的長短也和當前Generation中的對象數量有關,遍曆尋找20000個對象比起遍曆50個對象自然是要慢很多的。
    雖然Google的工程師在盡量縮短每次GC所花費的時間,但是特別注意GC引起的效能問題還是很有必要。如果不小心在最小的for迴圈單元裡面執行了建立對象的操作,這將很容易引起GC並導致效能問題。通過MemoryMonitor我們可以查看到記憶體的佔用情況,每一次瞬間的記憶體降低都是因為此時發生了GC操作,如果在短時間內發生大量的記憶體上漲與降低的事件,這說明很有可能這裡有效能問題。我們還可以通過HeapandAllocationTracker工具來查看此時記憶體中分配的到底有哪些對象。
    11)PerformanceCostofMemoryLeaks
    雖然Java有自動回收的機制,可是這不意味著Java中不存在記憶體流失的問題,而記憶體流失會很容易導致嚴重的效能問題。
    記憶體流失指的是那些程式不再使用的對象無法被GC識別,這樣就導致這個對象一直留在記憶體當中,佔用了寶貴的記憶體空間。顯然,這還使得每級Generation的記憶體地區可用空間變小,GC就會更容易被觸發,從而引起效能問題。
    尋找記憶體流失並修複這個漏洞是件很棘手的事情,你需要對執行的代碼很熟悉,清楚的知道在特定環境下是如何啟動並執行,然後仔細排查。例如,你想知道程式中的某個activity退出的時候,它之前所佔用的記憶體是否有完整的釋放乾淨了?首先你需要在activity處於前台的時候使用HeapTool擷取一份目前狀態的記憶體快照,然後你需要建立一個幾乎不這麼佔用記憶體的空白activity用來給前一個Activity進行跳轉,其次在跳轉到這個空白的activity的時候主動調用System.gc()方法來確保觸發一個GC操作。最後,如果前面這個activity的記憶體都有全部正確釋放,那麼在空白activity被啟動之後的記憶體快照中應該不會有前面那個activity中的任何對象了。
    如果你發現在空白activity的記憶體快照中有一些可疑的沒有被釋放的對象存在,那麼接下去就應該使用AlocationTrackTool來仔細尋找具體的可疑對象。我們可以從空白activity開始監聽,啟動到觀察activity,然後再回到空白activity結束監聽。這樣操作以後,我們可以仔細觀察那些對象,找出記憶體流失的真兇。
    12)MemoryPerformance
    通常來說,Android對GC做了大量的最佳化操作,雖然執行GC操作的時候會暫停其他任務,可是大多數情況下,GC操作還是相對很安靜並且高效的。但是如果我們對記憶體的使用不恰當,導致GC頻繁執行,這樣就會引起不小的效能問題。
    為了尋找記憶體的效能問題,AndroidStudio提供了工具來協助開發人員。
    MemoryMonitor:查看整個app所佔用的記憶體,以及發生GC的時刻,短時間內發生大量的GC操作是一個危險的訊號。
    AllocationTracker:使用此工具來追蹤記憶體的分配,前面有提到過。
    HeapTool:查看當前記憶體快照,便於對比分析哪些對象有可能是泄漏了的,請參考前面的Case。
    13)Tool-MemoryMonitor
    AndroidStudio中的MemoryMonitor可以很好的幫組我們查看程式的記憶體使用量情況。
    14)BatteryPerformance
    電量其實是目前手持功能最寶貴的資源之一,大多數裝置都需要不斷的充電來維持繼續使用。不幸的是,對於開發人員來說,電量最佳化是他們最後才會考慮的的事情。但是可以確定的是,千萬不能讓你的應用成為消耗電量的大戶。
    PurdueUniversity研究了最受歡迎的一些應用的電量消耗,平均只有30%左右的電量是被程式最核心的方法例如繪製圖片,擺放布局等等所使用掉的,剩下的70%左右的電量是被上報資料,檢查位置資訊,定時檢索後台廣告資訊所使用掉的。如何平衡這兩者的電量消耗,就顯得非常重要了。
    有下面一些措施能夠顯著減少電量的消耗:
    我們應該盡量減少喚醒螢幕的次數與持續的時間,使用WakeLock來處理喚醒的問題,能夠正確執行喚醒操作並根據設定及時關閉操作進入睡眠狀態。
    某些非必須馬上執行的操作,例如上傳歌曲,圖片處理等,可以等到裝置處於充電狀態或者電量充足的時候才進行。
    觸發網路請求的操作,每次都會保持無線訊號持續一段時間,我們可以把零散的網路請求打包進行一次操作,避免過多的無線訊號引起的電量消耗。關於網路請求引起無線訊號的電量消耗,還可以參考這裡。
    我們可以通過手機設定選項找到對應App的電量消耗統計資料。我們還可以通過BatteryHistorianTool來查看詳細的電量消耗。
    如果發現我們的App有電量消耗過多的問題,我們可以使用JobSchedulerAPI來對一些任務進行定時處理,例如我們可以把那些任務重的操作等到手機處於充電狀態,或者是串連到WiFi的時候來處理。
    15)UnderstandingBatteryDrainonAndroid
    電量消耗的計算與統計是一件麻煩而且矛盾的事情,記錄電量消耗本身也是一個費電量的事情。唯一可行的方案是使用第三方監測電量的裝置,這樣才能夠擷取到真實的電量消耗。
    當裝置處於待機狀態時消耗的電量是極少的,以N5為例,開啟飛航模式,可以待機接近1個月。可是點亮螢幕,硬體各個模組就需要開始工作,這會需要消耗很多電量。
    使用WakeLock或者JobScheduler喚醒裝置處理定時的任務之後,一定要及時讓裝置回到初始狀態。每次喚醒無線訊號進行資料傳遞,都會消耗很多電量,它比WiFi等操作更加的耗電。修複電量的消耗是另外一個很大的課題,這裡就不展開繼續了。
    16)BatteryDrainandWakeLocks
    高效的保留更多的電量與不斷促使使用者使用你的App來消耗電量,這是矛盾的選擇題。不過我們可以使用一些更好的辦法來平衡兩者。
    假設你的手機裡面裝了大量的社交類應用,即使手機處於待機狀態,也會經常被這些應用喚醒用來檢查同步新的資料資訊。Android會不斷關閉各種硬體來延長手機的待機時間,首先螢幕會逐漸層暗直至關閉,然後CPU進入睡眠,這一切操作都是為了節約寶貴的電量資源。但是即使在這種睡眠狀態下,大多數應用還是會嘗試進行工作,他們將不斷的喚醒手機。一個最簡單的喚醒手機的方法是使用PowerManager.WakeLock的API來保持CPU工作並防止螢幕變暗關閉。這使得手機可以被喚醒,執行工作,然後回到睡眠狀態。知道如何擷取WakeLock是簡單的,可是及時釋放WakeLock也是非常重要的,不恰當的使用WakeLock會導致嚴重錯誤。例如網路請求的資料返回時間不確定,導致本來只需要10s的事情一直等待了1個小時,這樣會使得電量白白浪費了。這也是為何使用帶逾時參數的wakelock.acquice()方法是很關鍵的。但是僅僅設定逾時並不足夠解決問題,例如設定多長的逾時比較合適?什麼時候進行重試等等?
    解決上面的問題,正確的方式可能是使用非精準定時器。通常情況下,我們會設定一個時間進行某個操作,但是動態修改這個時間也許會更好。例如,如果有另外一個程式需要比你設定的時間晚5分鐘喚醒,最好能夠等到那個時候,兩個任務捆綁一起同時進行,這就是非精確定時器的核心工作原理。我們可以定製計劃的任務,可是系統如果檢測到一個更好的時間,它可以延遲你的任務,以節省電量消耗。
    這正是JobSchedulerAPI所做的事情。它會根據當前的情況與任務,組合出理想的喚醒時間,例如等到正在充電或者串連到WiFi的時候,或者集中任務一起執行。我們可以通過這個API實現很多免費的調度演算法。
    從Android5.0開始發布了BatteryHistoryTool,它可以查看程式被喚醒的頻率,又誰喚醒的,持續了多長的時間,這些資訊都可以擷取到。
    請關注程式的電量消耗,使用者可以通過手機的設定選項觀察到那些耗電量大戶,並可能決定卸載他們。所以盡量減少程式的電量消耗是非常有必要的。
    更多:黑帽技術 http://www.heimaoxuexi.com

Android效能最佳化典範

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.