【Android開發】Android性能優化

Android性能優化

    根據Android的層次結構,性能優化也是分層次進行的,本文會分別對Application、Framework、Native、Kernel各層作總結,每層主要會從性能優化的基本思想、優化技巧、優化工具幾個方面進行說明。html

第一章Android應用性能優化(概述)

    應用程序的性能問題是最明顯、最容易體現的一類,表現形式也五花八門,舉幾個例子:node

  • 應用程序第一次啓動速度慢,或者進入某一界面速度慢;
  • 啓動某一有動畫效果的界面,動畫執行過程不流暢,或者動畫執行前卡頓時間長;
  • ListView列表滑動過程當中卡頓,不流暢;
  • 應用程序自定義的某特定界面執行速度慢,例如Launcher應用桌面左右滑動效果不平滑;
  • 響應某一用戶事件時長時間無響應(ANR);
  • 操做數據庫時,執行大量數據的增刪改查操做,執行速度慢;
  • 應用長時間運行後,隨機出現卡頓現象;

       除了表現形式複雜,緣由也很複雜。以上的問題的緣由可能不僅一個,而且不少狀況下並非應用自己的問題,也有多是系統其餘層次有問題,只不過體如今應用層。因此說應用層老是首當其衝,開發人員在處理性能問題時,須要作的第一件事情就是判斷是不是應用自身引發的性能問題,而後再對症下藥;但有些時候應用自己邏輯正常,明顯是系統的硬件配置不足引發,此時就要根據產品或項目需求,採起一些更加激進的方式優化性能,以彌補硬件配置的不足。android

        如下從幾個不一樣的角度總結一下應用程序性能優化的一些方法。算法

1、基本思想

        應用層的性能優化一般能夠從如下幾個方面考慮:數據庫

1. 瞭解編程語言的編譯原理,使用高效編碼方式從語法上提升程序性能;編程

2. 採用合理的數據結構和算法提升程序性能,這每每是決定程序性能的關鍵;瀏覽器

3. 重視界面佈局優化;緩存

4. 採用多線程、緩存數據、延遲加載、提早加載等手段,解決嚴重的性能瓶頸;性能優化

5. 合理配置虛擬機堆內存使用上限和使用率,減小垃圾回收頻率;數據結構

6. 合理使用native代碼;

7. 合理配置數據庫緩存類型和優化SQL語句加快讀取速度,使用事務加快寫入速度;

7. 使用工具分析性能問題,找出性能瓶頸;

       固然確定還有不少其餘的性能優化方法,此處僅列出一些常常會用到的方法。限於篇幅,如下會對其中一部份內容作介紹,但願可以對你們作性能優化工做有所幫助。

2、編程技巧

(一)Performance Tips (For Java)

       Google官網上有一些關於應用程序性能提高的技巧,以前公司內也有不少總結提到過,在此簡單羅列一下,詳細內容能夠從官網獲取。

http://developer.android.com/training/articles/perf-tips.html

須要說明的是,文章列出的優化技巧主要是一些微小的性能提高,決定程序總體性能的仍然取決於程序的業務邏輯設計、代碼的數據結構和算法。研發人員須要將這些優化技巧應用到平時的編碼過程當中,聚沙成塔,也會對性能有很大的影響。

寫出高效的代碼須要遵循兩條原則:

  • 不執行沒必要要的操做;
  • 不分配沒必要要的內存;

       兩條原則分別針對CPU和內存,完成必要操做的前提下儘量的節省CPU和內存資源,天然執行效率要高。單純這樣說聽起來很虛,畢竟沒有一個統一的標準判斷什麼是必要和沒必要要的,須要結合具體狀況具體分析了。

     1. 避免建立沒必要要的對象

       建立太多的對象會形成性能低下,這誰都知道,但是爲何呢?首先分配內存自己須要時間,其次虛擬機運行時堆內存使用量是有上限的,當使用量到達必定程度時會觸發垃圾回收,垃圾回收會使得線程甚至是整個進程暫停運行。可想而知,若是有對象頻繁的建立和銷燬,或者內存使用率很高,就會形成應用程序嚴重卡頓。

     2.合理使用static成員

     主要有三點須要掌握:

  • 若是一個方法不須要操做運行時的動態變量和方法,那麼能夠將方法設置爲static的。
  • 常量字段要聲明爲「static final」,由於這樣常量會被存放在dex文件的靜態字段初始化器中被直接訪問,不然在運行時須要經過編譯時自動生成的一些函數來初始化。此規則只對基本類型和String類型有效。
  • 不要將視圖控件聲明爲static,由於View對象會引用Activity對象,當Activity退出時其對象自己沒法被銷燬,會形成內存溢出。

       3. 避免內部的Getters/Setters

       面向對象設計中,字段訪問使用Getters/Setters一般是一個好的原則,可是在Android開發中限於硬件條件,除非字段須要被公開訪問,不然若是隻是有限範圍內的內部訪問(例如包內訪問)則不建議使用Getters/Setters。在開啓JIT時,直接訪問的速度比間接訪問要快7倍。

       4. 使用for-each循環

       優先使用for-each循環一般狀況下會得到更高的效率;除了一種狀況,即對ArrayList進行遍歷時,使用手動的計數循環效率要更高。

       5. 使用package代替private以便私有內部類高效訪問外部類成員

       私有內部類的方法訪問外部類的私有成員變量和方法,在語法上是正確的,可是虛擬機在運行時並非直接訪問的,而是在編譯時會在外部類中自動生成一些包級別的靜態方法,執行時內部類會調用這些靜態方法來訪問外部類的私有成員。這樣的話就多了一層方法調用,性能有所損耗。

一種解決這個問題的方法就是將外部類的私有成員改成包級別的,這樣內部類就能夠直接訪問,固然前提是設計上可接受。

       6. 避免使用浮點類型

       經驗之談,在Android設備中浮點型大概比整型數據處理速度慢兩倍,因此若是整型能夠解決的問題就不要用浮點型。

       另外,一些處理器有硬件乘法可是沒有除法,這種狀況下除法和取模運算是用軟件實現的。爲了提升效率,在寫運算式時能夠考慮將一些除法操做直接改寫爲乘法實現,例如將「x / 2」改寫爲「x * 0.5」。

       7. 瞭解並使用庫函數

Java標準庫和Android Framework中包含了大量高效且健壯的庫函數,不少函數還採用了native實現,一般狀況下比咱們用Java實現一樣功能的代碼的效率要高不少。因此善於使用系統庫函數能夠節省開發時間,而且也不容易出錯。

(二)佈局性能優化

       佈局直接影響到界面的顯示時間。關於界面佈局的性能優化在技術上並無難點,我的認爲最重要的是是否定識到佈局優化的重要性。起初我也會以爲佈局自己不會是性能瓶頸,而且也很難優化,好不容易寫了複雜的佈局文件,或者原生代碼就是那樣,並且也用log查看了setContentView的時間,彷佛沒什麼問題,實在是不想去研究。但實際上佈局問題沒有想象的那麼簡單。

佈局的性能優化之因此重要,由於如下兩個方面:

·           佈局文件是一個xml文件,inflate佈局文件其實就是解析xml,根據標籤信息建立相應的佈局對象並作關聯。xml中的標籤和屬性設置越多,節點樹的深度越深,在解析時要執行的判斷邏輯、函數的嵌套和遞歸就越多,因此時間消耗越多;

·        inflate操做只是佈局影響的第一個環節,一個界面要顯示出來,在requestLayout後還要執行一系列的measure、layout、draw的操做,每一步的執行時間都會受到佈局自己的影響。而界面的最終顯示是全部這些操做完成後才實現的,因此若是佈局質量差,會增長每一步操做的時間成本,最終顯示時間就會比較長。

       那麼佈局如何優化?總結以下幾點:

     1. 遵循一條規則:佈局層次儘可能少

也就是說,在達到一樣佈局效果的前提下,xml文件中樹的深度儘可能的潛。要作到這一點須要合理的使用佈局控件:

  • 典型的狀況是你可使用RelativeLayout來代替LinearLayout實現相同的佈局效果;
  • 還有一種是若是佈局樹的A節點只有一個子節點B,而B只有一個子節點C,那麼B一般是能夠去掉的;
  • 合理的使用<merge>標籤,若是佈局X能夠被include到Y中,那麼須要考慮X的根節點是否能夠設置爲<merge>,這樣在解析時會將<merge>的子節點添加到Y中,而<merge>自己不會添加。

     2. 使用Lint分析佈局

       Lint是SDK中tools目錄下的工具,ADT中集成了Lint的可視化控制界面。用Lint掃描應用程序,它會從不少方面對應用進行分析,並提示那些可能有缺陷的地方,其中就包含與性能相關的內容。你能夠在Google官網上了解詳細信息。

http://developer.android.com/tools/debugging/improving-w-lint.html

http://developer.android.com/tools/help/lint.html

     3. 使用HierarchyViewer分析佈局

       HierarchyViewer(如下簡稱HV)也是SDK中tools目錄下的工具,ADT中也集成了HV的可視化控制界面。可使用HV查看當前界面的佈局,它能提供不少信息,其中有兩個能夠幫助咱們分析性能問題:

·           HV的樹視圖展示了視圖控件的相互關係,能夠用來檢查是否有第1點中提到的狀況。

·          樹視圖中能夠顯示每一個節點measure、layout、draw的時間,而且每一項用一個圓點表示其耗時是否正常,每一個圓點分別用綠色、黃色、紅色表示耗時正常、警告、危險,這樣就能夠很方便的找到有性能瓶頸了。若是樹視圖中沒有顯示這些時間,你能夠點擊「Obtain layout times for tree rooted at selected node」按鈕刷新界面顯示。

http://developer.android.com/tools/debugging/debugging-ui.html

       4. 使用ViewStub延遲加載視圖

       ViewStub是一個沒有尺寸大小而且不會在佈局中嵌套或渲染任何東西的輕量級的視圖。若是界面中有一部分視圖控件不須要當即顯示,則能夠將其寫到一個單獨的layout文件中,用ViewStub標籤代替,當要真正顯示這部份內容時再經過ViewStub將視圖加載進來。

http://developer.android.com/training/improving-layouts/loading-ondemand.html

3、工具使用

     遵循好的編碼習慣可讓程序執行更有效率,可是實際運行時仍然會遇到各類各樣的性能問題。幸虧有不少強大的工具能幫助咱們分析性能瓶頸,找到問題所在。如下介紹的工具想必你們已經很熟悉了,網上有不少相關文章寫的都很不錯,在此再也不贅述,僅對這些工具在使用時的一些關鍵點作一些說明。關於這些工具的詳細使用方法請見網上的一篇文章:http://blog.csdn.net/innost/article/details/9008691

(一)Traceview

       作性能優化的最直接的方法,就是復現有性能問題的場景,並監控此過程當中程序的執行流程,若是可以方便的分析程序中函數的調用關係和執行時間,天然也就很容易找出性能瓶頸了。

Traceview就是用來分析函數調用過程的工具,利用它能夠方便的分析性能問題。它的使用方式須要如下幾步:

  • 使用Android的Debug API,或者DDMS監控程序運行過程;
  • 復現有性能問題的場景,用第1步的方法獲取程序過程當中的函數調用日誌文件,即trace文件;
  • 使用Traceview導入trace文件便可;

       Traceview的界面很直觀,可是在分析過程當中須要特別注意如下幾點:

1. Profile Panel中的各列的含義

·         Incl – 指函數自己和內部嵌套的其餘函數的執行時間;

·         Excl -  指函數自己,不包含內部嵌套的其餘函數的執行時間;

·         Cpu Time – 指函數執行時所佔用的CPU時間片的總和,不包含等待調度的時間;

·         Real Time – 指函數執行過程的真實時間,包含等待調度的時間;

·         Cpu Time/Call – 指函數平均每次調用的CPU時間;

·         Real Time/Call – 指函數平均每次調用的真實時間;

·         Calls+Recur Calls/Total – 指函數調用的總次數+遞歸調用次數百分比;

·         % - 帶有%的列是指函數的執行時間佔總採樣時間的百分比;

     2. 如何分析性能瓶頸

       首先一般須要關心的是CPU時間,能夠找出程序自身的問題,真實時間會受到系統其餘因素的影響。而後能夠從四個方面進行分析:

1)分析有哪些函數單次執行時間長

       能夠點擊「Cpu Time/Call」一列,按照降序排列,並找出那些執行時間相對較長同時也是咱們關心的函數,而後再查看其函數內部的詳細執行過程;

2)分析有哪些函數調用次數過多

       能夠點擊「Calls+RecurCalls/Total」一列,按照降序排列,並找出哪些執行次數相對較多同時也是咱們關心的函數,而後再查看其函數內部的詳細執行過程;

3)分析有哪些函數總執行時間長

       有些函數的單次執行時間不是特別長,總調用次數也不是特別多,可是兩者相乘得出的總的執行時間較長,能夠點擊「Incl Cpu Time」,按照降序排列,找出這些函數;

4)有時咱們很明確須要查看一些特定類的特定方法,能夠在頁面最下方的搜索條中搜索,不過好像只支持全小寫輸入。

       3. 提示一點:利用API或工具採樣trace信息時,會禁用JIT功能,同時由於採樣自己也須要佔用系統資源,因此用Traceview查看函數的執行時間都要比正常運行時慢很多,咱們只要關心相對的時間消耗便可。

(二)dmtracedump

     trace文件除了能夠用TraceView分析外,還能夠利用另一個工具dmtracedump,它的功能也很強大。若是你以爲在Traceview中查找類和函數很痛苦,不妨試試這個工具。

dmtracedump是SDK的tools目錄下的可執行文件,你能夠查看它的幫助信息,並執行相似以下的命令:

dmtracedump -h -g tracemap.png path-to-your-trace-file > path-to-a-html-file.html

而後就能夠獲得兩樣東西,一個是各函數調用的樹狀圖,能夠一目瞭然的查看函數關係;另外一個是可操做的html的文件,用瀏覽器打開就能夠方便的查找你關心的類或函數。

(三)systrace

       Systrace是從4.1引入的一個強大的性能分析工具,依賴於Kernel的ftrace功能,能夠對系統中不少重要模塊,特別是圖形顯示模塊作性能分析。它功能包括跟蹤系統的I/O操做、內核工做隊列、CPU負載以及Android各個子系統的運行情況等。

       Systrace的使用方法也是須要先經過Android提供的API或者DDMS開啓跟蹤監控模式,而後運行程序生成日誌文件,最後分析日誌文件便可。Systrace輸出的是一個html文件,直接用瀏覽器查看便可。若是你使用最新版本的ADT,能夠很方便的經過界面操做,不用再用命令了。更詳細的內容能夠在網上搜索。

4、關於性能優化的思考

       性能優化是一個很大的話題,除了討論如何優化外,還有一個更重要的就是是否須要優化。早在幾十年前,就有不少關於性能優化的討論,而後得出一個深入的真理:優化更容易帶來傷害,而不是好處,特別是不成熟的優化。在優化過程當中,你產生的軟件可能既不快速,也不正確,並且還不容易被修正。

不要由於性能而犧牲合理的結構。努力編寫好的程序而不是快的程序。

       可是,這並不意味着,在完成程序以前你就能夠忽略性能問題。實現上的問題能夠經過後期的優化而被改正,但遍及全局而且限制性能的結構缺陷幾乎是不可能被改正的,除非從新編寫程序。在系統完成以後再改變你的設計的某個基本方面,會致使你的系統結構病態,從而難以維護和改進。所以你應該在設計過程當中考慮性能問題。

 

       努力避免那些限制性能的設計。考慮你的代碼設計的性能後果。爲得到好的性能而對代碼進行曲改,是一個很是很差的想法。在每次作優化以前和以後,須要對性能進行測量。

 

轉自:http://rayleeya.iteye.com/blog/1961005

相關文章
相關標籤/搜索