天天看點

android性能優化

性能優化本身是一個很大的主題,涵蓋程式的方方面面,任何不慎的操作,都有可能對性能造成比較大的影響,要知道程式的性能是可以累加的,多處的性能低下,會影響整體的性能,其後果可能也是多方面的,本文總結了目前工作中,所需要知道的大部分性能優化點,一部分個人總結,一部分來自于網際網路。但整體上,都是提綱性的,并沒有列出具體的執行個體,因為寫這方面主題的達人實在太多了,是以,我得站在巨人的肩膀上,具體細節,請參考對應的連結。

遊戲:界面很卡,fps低

搜尋性能差

伺服器響應速度慢

os:界面無響應

使用者流失

項目失敗

引發災難

硬體

io操作

資料庫

網絡

函數調用

資料結構

程式邏輯

….

硬體性能

架構設計

核心資料結構

……

小規模修改程式,提高性能:程式的性能是可以累加的

簡單代碼設計

類和函數設計:合适的資料類型和算法

用快速排序代替冒泡排序

用二分查找代替線性查找

業務邏輯的實作

高效代碼≠更好代碼≠高品質代碼(易修改,易擴充,易維護)

80/20法則:4%的代碼占用了50%以上的運作時間

随時随地進行優化 ==>将陷入無休止的優化泥潭

開發階段前期:功能都未實作,何談優化,但在設計的時候,需要考慮到對應風險。

開發階段中後期:功能部分完善,通過現象進行子產品優化

開發階段後期:功能完善,充分考慮整體性,通過現象進行系統優化

後期優化無法滿足性能要求----架構先天不足,隻能大批量重構

過分提高性能會損害程式的可讀性和可維護性

優先實作功能,然後再進行優化

程式功能的正确性比性能更重要

真正高性能的程式設計:

more small, more fast

more simple, more fast

在進行性能優化前,確定該功能是否已基本完整。

android性能優化

key points

是否考慮通過修改需求來提高性能?

是否考慮通過修改整體設計提高性能?

是否考慮通過來修改類的設計提高性能?

在開始修改前,程式是完全正确的麼?

是否在修改前是否進行性能評估?

是否記錄了每次修改後的性能的變化?

如果沒有帶來預期的性能提高,是否完全放棄所做的代碼調整?

是否對每個性能瓶頸進行不止一次的嘗試?

是否反複進行代碼調整,直到最優?

找出瓶頸,集中火力對付占用絕大部分資源的少量代碼。

途徑:

code review

通過最基本優化政策優化代碼

代碼性能測量

1) 通過性能log記錄函數調用時間,找出瓶頸點

    logutil.d(tagconstant.tag_performance,"load media info into group begin......");

    longstart = system.currenttimemillis();

                 ……

    logutil.d(tagconstant.tag_performance,“load media info into group end, total time: ” + (system.currenttimemillis() -start) + “ ms”);

2) 使用性能分析工具:

    monkey

    monkeyrunner

     注:後兩個我個人沒有使用過,不做介紹,優先推薦使用traceview工具 

優化本身是一個很大的主題,我這是主要是針對于android平台來說的。個人認為,優化可以分成好幾部分:

一是java文法層次通用的優化,如盡量使用局部變量(棧變量),io緩沖等。

二是通用的android性能優化,如同步改異步,各種緩存的使用等

三是應用程式内部的性能優化,如内部邏輯、資料插入及查找、資料結構的安排與組織等

以下部分針對于上述3種類型,分别進行簡要說明:

類和對象使用技巧

盡量少用new生成新對象

使用clone方法生成新對象

盡量使用局部變量棧變量

減少方法調用

使用final類和final/static/private方法

讓通路執行個體内變量的 getter/setter

方法變成final  

避免不需要的 instanceof 操作  

避免不需要的造型操作  

盡量重用對象  

不要重複初始化變量  

不要過分建立對象

java io技巧

使用緩沖提高io性能

lnputstream比reader高效,outputstream比writer高效

在适當的時候用byte替代char

有緩沖的塊操作io要比緩沖的流字元io快

序列化時使用原子類型

在finally塊中關閉stream 

sql語句

盡早釋放資源

異常exceptions使用技巧

避免使用異常來控制程式流程

盡可能重用異常

将trycatch 塊移出循環  

線程使用技巧

在使用大量線程threading的場合使用線程池管理

防止過多的同步

同步方法而不要同步整個代碼段

在追求速度的場合用arraylist和hashmap代替vector和hashtable

使用notify而不是notifyall

不要在循環中調用 synchronized同步方法   

單線程應盡量使用 hashmap,arraylist

其它常用技巧

使用移位操作替代乘除法操作可以極大地提高性能

對vector中最後位置的添加删除操作要遠遠快于埘第一個元素的添加删除操作

當複制數組時使用system.arraycop方法

使用複合指派運算符

用int而不用其它基本類型

在進行資料庫連接配接和網絡連接配接時使用連接配接池

用壓縮加快網絡傳輸速度一種常用方法是把相關檔案打包到一個jar檔案中

在資料庫應用程式中使用批處理功能

消除循環體中不必要的代碼

為vectors 和 hashtables定義初始大小  

如果隻是查找單個字元的話用charat代替startswith

在字元串相加的時候使用 charat()代替startswith() 如果該字元串隻有一個字元的話  

對于 boolean 值避免不必要的等式判斷  

對于常量字元串用string 代替 stringbuffer   

用stringtokenizer 代替 indexof 和substring  

使用條件操作符替代if cond else  結構 

不要在循環體中執行個體化變量  

确定 stringbuffer的容量  

不要總是使用取反操作符  

與一個接口 進行instanceof 操作  

采用在需要的時候才開始建立的政策  

通過 stringbuffer 的構造函數來設定他的初始化容量可以明顯提升性能  

合理使用 javautilvector

不要将數組聲明為public static final

haspmap 的周遊

array數組和 arraylist 的使用  

stringbufferstringbuilder 的差別

盡量使用基本資料類型代替對象   

用簡單的數值計算代替複雜的函數計算比如查表方式解決三角函數問題  

使用具體類比使用接口效率高但結構彈性降低了但現代 ide都可以解決這個問題 

考慮使用靜态方法

應盡可能避免使用内在的get/set 方法 

避免枚舉浮點數的使用   

二維數組比一維數組占用更多的記憶體空間大概是 10倍計算 

sqlite

奇偶判斷

實際上,android本身的training文檔也提供給我們很多可參考的内容,以下僅枚舉一些keypoint,當然,有的内容是與上面的政策是重複的。

總體上來說,想要寫出高效代碼,我們要遵循兩條基本的原則:

不作沒有必要的工作。

盡量避免記憶體配置設定。

key point:

避免建立不必要的對象

用靜态代替虛拟

避免内部的getters/setters

對常量使用static final修飾符

使用改進的for循環文法(for-each)

在有内部類的情況考慮使用包權限來替代私有通路

避免使用浮點數

了解并使用類庫

合理利用native方法

布局優化

盡量減少android程式布局中view的層次,view層次越多,效率就越低

使用<include/>複用布局

使用viewholder、thread使listview滾動更加流暢

其它優化點

合理使用異步操作

懶加載:目前不需要的資料,不要加載,即按需加載。懶加載的範圍是廣泛的,可以是資料,可以是view,或者其它

使用緩存

圖檔緩存:包括memorycache和diskcache,推薦使用官方demo中的cache

單例資料緩存:建立一個管理資料的類,管理所有資料,當主界面消失後,由于application本身沒有實際退出,是以,資料本身也沒有釋放掉,下次啟動時,省去了加載資料的時間,當然,這并不是一個好的行為。

使用listview、gridview的view緩存

使用message自身的緩存,避免重複建立message執行個體

線程池

資料池(可參考message pool的實作方式)

資料庫優化

sql優化

建立索引

使用事務

…...

算法優化

資料結構使用

不要全部使用arraylist,合理使用linkedlist等易于插入和删除的集合

合理使用hashmap、hashset來提高查找性能

使用sparsearray、sparseintarray、sparsebooleanarray來替代某些特定的hashmap

其它政策

可以考慮延遲處理,避免在同一時間幹過多的事情

該部分的優化應該是依據程式的不同而不同,沒有萬般皆準的法則,目前從我做過的程式來看,實際上,上述的性能優化點基本上已經能夠解決很多性能問題了。

在我所做的程式中,主要的優化手段是:

程式邏輯簡化:分析代碼,去掉備援邏輯

資料結構的優化:對集合類的靈活使用,特别是hashmap的使用,極大的提高查找性能。

批量處理原則:對于需要循環調用地方,采用批量處理

性能優化本身是對代碼的重構和反思過程,通過優化性能,能找出我們很多設計、邏輯上的不足。

優化的過程往往很痛苦,但在做過這個過程後,個人在程式設計水準、設計水準上都會有很大的提高。

很多優化的思想應該做為編碼規範的一部分,需要我們反複實踐,在寫代碼時,第一反應所得出的代碼就是最優的。