偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Android性能優(yōu)化之被忽視的優(yōu)化點(diǎn)

移動(dòng)開(kāi)發(fā) Android
對(duì)于性能優(yōu)化這個(gè)知識(shí)點(diǎn)來(lái)說(shuō),實(shí)在是太廣了,博主本人也一直非常關(guān)注這方面的學(xué)習(xí),而對(duì)于性能優(yōu)化來(lái)說(shuō)它包括了非常非常非常多方面,比如:I/O的優(yōu)化、網(wǎng)絡(luò)操作的優(yōu)化、內(nèi)存的優(yōu)化、數(shù)據(jù)結(jié)構(gòu)的優(yōu)化、代碼層次的優(yōu)化、UI渲染優(yōu)化、CPU資源使用率的優(yōu)化、異常處理的優(yōu)化等等等等。。。

對(duì)于性能優(yōu)化這個(gè)知識(shí)點(diǎn)來(lái)說(shuō),實(shí)在是太廣了,博主本人也一直非常關(guān)注這方面的學(xué)習(xí),而對(duì)于性能優(yōu)化來(lái)說(shuō)它包括了非常非常非常多方面,比如:I/O的優(yōu)化、網(wǎng)絡(luò)操作的優(yōu)化、內(nèi)存的優(yōu)化、數(shù)據(jù)結(jié)構(gòu)的優(yōu)化、代碼層次的優(yōu)化、UI渲染優(yōu)化、CPU資源使用率的優(yōu)化、異常處理的優(yōu)化等等等等。。。

[[181654]]

本篇文章就博主本人的理解來(lái)講述一些在Android開(kāi)發(fā)中可以優(yōu)化的地方

ArrayList和Vector

ArrayList和Vector都是內(nèi)部以數(shù)組實(shí)現(xiàn)的List,它們兩唯一的區(qū)別就是對(duì)多線程的支持,ArrayList是線程不安全的,而Vector內(nèi)部對(duì)大多數(shù)方法都做了同步,是線程安全的,既然是線程安全的,所以性能方面肯定不如ArrayList了(當(dāng)然想法肯定是對(duì)的),不過(guò)這需要看哪方面了,ArrayList在add、get、remove等操作效率肯定是高于Vector的,而在內(nèi)存方面,Vector卻比ArrayList表現(xiàn)的更好,這歸根都是ArrayList的擴(kuò)容策略導(dǎo)致的,稍后分析。

實(shí)現(xiàn)RandomAccess接口的集合使用fori遍歷

先談?wù)凩ist集合的遍歷方式,有三種:foreach、iterator、fori。

而在開(kāi)發(fā)中一般需要遍歷時(shí)首選肯定是foreach了,因?yàn)樗矢?,這個(gè)觀點(diǎn)沒(méi)錯(cuò),不過(guò)需要分場(chǎng)合了。

下面是我用這三種方式測(cè)試遍歷有100w條數(shù)據(jù)的ArrayList集合:

  1. long start = System.currentTimeMillis(); 
  2. for (int i = 0; i < size; i++) { 
  3. data.get(i); 
  4. long end = System.currentTimeMillis(); 
  5. Log.v("zxy","fori花費(fèi):"+(end-start)); 
  6.  
  7. start = System.currentTimeMillis(); 
  8. for (Integer integer : data) { 
  9.  
  10. end = System.currentTimeMillis(); 
  11. Log.v("zxy","foreach花費(fèi):"+(end-start)); 
  12.  
  13. Iterator<Integer> iterator = data.iterator(); 
  14. start = System.currentTimeMillis(); 
  15. while (iterator.hasNext()){ 
  16. iterator.next(); 
  17. end = System.currentTimeMillis(); 
  18. Log.v("zxy","iterator花費(fèi):"+(end-start)); 
  19.  
  20. 11-19 09:11:44.276 1418-1418/? V/zxy: fori花費(fèi):30 
  21. 11-19 09:11:44.380 1418-1418/? V/zxy: foreach花費(fèi):105 
  22. 11-19 09:11:44.476 1418-1418/? V/zxy: iterator花費(fèi):95  

而通常我們所說(shuō)的效率高的foreach在遍歷上卻顯得不如意,而fori效率表現(xiàn)的最好,這是因?yàn)锳rrayList和Vector集合內(nèi)部實(shí)現(xiàn)由數(shù)組實(shí)現(xiàn),所以隨機(jī)訪問(wèn)的速度是很快的,對(duì)于可以進(jìn)行隨機(jī)訪問(wèn)的List,JDK為它們實(shí)現(xiàn)了RandomAccess接口,表示支持快速隨機(jī)訪問(wèn)。

而在遍歷有1w條數(shù)據(jù)的LinkedList集合時(shí):

  1. 11-19 09:33:23.984 1737-1737/? V/zxy: fori花費(fèi):351 
  2. 11-19 09:33:23.988 1737-1737/? V/zxy: foreach花費(fèi):2 
  3. 11-19 09:33:23.992 1737-1737/? V/zxy: iterator花費(fèi):4  

則foreach表現(xiàn)最佳,所以對(duì)數(shù)組、或者實(shí)現(xiàn)了RandomAccess接口的List,遍歷用fori性能最佳,對(duì)LinkedList等以鏈表實(shí)現(xiàn)的集合遍歷時(shí)使用foreach或者iterator性能最佳,因?yàn)閒oreach的實(shí)現(xiàn)就是通過(guò)iterator實(shí)現(xiàn)的。

我們可以這樣判斷該List遍歷用哪種方式:

  1. if (list instanceof RandomAccess) 
  2. for (int i = 0; i < list.size(); i++) {} 
  3. else { 
  4. Iterator<?> iterator = list.iterator(); 
  5. while (iterator.hasNext()) { 
  6. iterator.next(); 
  7.  

預(yù)知容量的情況下構(gòu)造ArrayList時(shí)盡量指定初始大小

ArrayList內(nèi)部的擴(kuò)容策略是當(dāng)其所存儲(chǔ)的元素?cái)?shù)量超過(guò)它已有的大小時(shí),它就會(huì)以1.5倍的容量進(jìn)行擴(kuò)容,也就是假如當(dāng)前ArrayList的容量為10000,那么它在需要再存儲(chǔ)一個(gè)元素時(shí),即第10001個(gè)元素,由于容量不夠而進(jìn)行一次擴(kuò)容,而ArrayList擴(kuò)容后的容量則變?yōu)榱?5000,而多出了一個(gè)元素就多了5000個(gè)元素的空間,這太浪費(fèi)內(nèi)存資源了,而且擴(kuò)容還會(huì)導(dǎo)致整個(gè)數(shù)組進(jìn)行一次內(nèi)存復(fù)制,而ArrayList集合默認(rèn)大小為10,因此合理的設(shè)置ArrayList的容量可避免集合進(jìn)行擴(kuò)容。ArrayList內(nèi)部擴(kuò)容和數(shù)組復(fù)制代碼為:

  1. Object[] newArray = new Object[s + 
  2. (s < (MIN_CAPACITY_INCREMENT / 2) ? 
  3. MIN_CAPACITY_INCREMENT : s >> 1)]; 
  4. System.arraycopy(a, 0, newArray, 0, s); 
  5. array = a = newArray;  

而Vector內(nèi)部擴(kuò)容策略為按需擴(kuò)容,每次+1:

  1. if (capacityIncrement <= 0) { 
  2. if ((adding = elementData.length) == 0) { 
  3. adding = 1; 
  4. else { 
  5. adding = capacityIncrement; 
  6.  
  7. E[] newData = newElementArray(elementData.length + adding);  

同樣,在眾多Map集合中也有各自擴(kuò)容策略,比如HashMap每次擴(kuò)容時(shí)新容量等于原始的容量*2。在我們常用做字符串拼接的StringBuffer和StringBuilder內(nèi)部,實(shí)際上也是有擴(kuò)容策略,默認(rèn)為擴(kuò)容為原始的1.5倍。

所以,在這些需要擴(kuò)容的api上,如果預(yù)先知道了數(shù)據(jù)的大小,則預(yù)先設(shè)置,這樣不僅可以避免擴(kuò)容導(dǎo)致的空間浪費(fèi),而且還可避免內(nèi)部調(diào)用System.arraycopy()進(jìn)行大量數(shù)據(jù)復(fù)制。

程序如果需要通過(guò)索引下標(biāo)對(duì)List做隨機(jī)訪問(wèn),應(yīng)優(yōu)先考慮ArrayList和Vector,迫不得已盡量不要使用LinkedList

雖說(shuō)ArrayList在內(nèi)存上比不上Vector,不過(guò)它對(duì)數(shù)據(jù)操作的效率高,特別是在Android等移動(dòng)設(shè)備上,采取犧牲一點(diǎn)空間換時(shí)間的方式還是可取的,而涉及到線程安全方面,則使用Vector。

如果一個(gè)方法不需要使用該對(duì)象的成員,那么把該方法設(shè)為static

靜態(tài)調(diào)用該方法比對(duì)象調(diào)用該方法快15%~20%,因?yàn)檫@樣可以從方法簽名上就可以看出該方法調(diào)用不會(huì)影響該對(duì)象的狀態(tài)

巧用final關(guān)鍵字

final關(guān)鍵字一般在定義常量和方法用的比較多,而大多數(shù)人對(duì)final的理解往往是在不可變性上,而final對(duì)性能優(yōu)化也有很大的作用。

比如:static int AGE = 10;當(dāng)10在后面被引用時(shí),這時(shí)會(huì)有一個(gè)字段查找的過(guò)程,對(duì)于int類(lèi)型也就是查找方法區(qū)中的整型常量池,而對(duì)于final的常量,則省去了這個(gè)過(guò)程,比如:static final int AGE = 10;在使用到AGE的地方將直接用10代替。

不過(guò)對(duì)于上面這種優(yōu)化技巧,僅對(duì)基本類(lèi)型和String類(lèi)型有效,對(duì)于其它的引用類(lèi)型則無(wú)效,但是我們?cè)诼暶鞒A康臅r(shí)候加上 static final 依然是個(gè)好習(xí)慣

對(duì)與final關(guān)鍵字,還有一個(gè)強(qiáng)大的作用,就是對(duì)那些使用頻繁、已經(jīng)確定為終態(tài)的方法定義final,這樣有什么好處呢?

說(shuō)這個(gè)前先來(lái)說(shuō)說(shuō)java中方法的執(zhí)行過(guò)程吧,當(dāng)調(diào)用某個(gè)方法時(shí),首先這個(gè)方法會(huì)入棧,執(zhí)行完畢后,這個(gè)方法出棧,資源釋放,而這個(gè)過(guò)程內(nèi)部其實(shí)是內(nèi)存地址的轉(zhuǎn)移過(guò)程,當(dāng)執(zhí)行入棧的方法時(shí),其實(shí)就是把程序的執(zhí)行地址轉(zhuǎn)移到該方法存放的內(nèi)存地址中,而做此操作前,還有必須進(jìn)行原先程序執(zhí)行的內(nèi)存地址保存過(guò)程,當(dāng)方法執(zhí)行完出棧后則繼續(xù)按保存的地址繼續(xù)執(zhí)行程序,而這個(gè)過(guò)程,就是方法的調(diào)用過(guò)程。

所以,方法的調(diào)用過(guò)程實(shí)際上是需要空間和時(shí)間的,而對(duì)于同一個(gè)方法的頻繁調(diào)用的優(yōu)化實(shí)際上就是使用內(nèi)聯(lián)的辦法。

又說(shuō)到內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)函數(shù)實(shí)際上是在編譯期做的優(yōu)化,編譯器會(huì)將標(biāo)為為內(nèi)聯(lián)的函數(shù)在其調(diào)用的地方直接用整個(gè)函數(shù)體進(jìn)行替換掉,這就省去了函數(shù)調(diào)用所耗去的時(shí)間資源了,而換來(lái)的卻是目標(biāo)代碼量的增加,所以內(nèi)聯(lián)這種優(yōu)化策略實(shí)際上是采取了以空間換時(shí)間的策略,對(duì)于移動(dòng)端來(lái)說(shuō),巧用內(nèi)聯(lián)函數(shù)實(shí)則非常有益。

而要是一個(gè)函數(shù)成為內(nèi)聯(lián)函數(shù),就是將它定義為final,這樣在程序編譯時(shí),編譯器會(huì)自動(dòng)將final函數(shù)進(jìn)行內(nèi)聯(lián)優(yōu)化,那么在調(diào)用該函數(shù)時(shí)則直接展開(kāi)該函數(shù)體進(jìn)行使用。

總結(jié),并不是內(nèi)聯(lián)函數(shù)越多越好,一方面它對(duì)我們程序的運(yùn)行效率上確實(shí)有提升,而另一方面,對(duì)于過(guò)多的使用內(nèi)聯(lián)函數(shù),則會(huì)弄巧成拙,有可能會(huì)把某個(gè)方法的方法體越搞越大,而且對(duì)于某些方法體比較大的方法,內(nèi)聯(lián)展開(kāi)的時(shí)間有可能超過(guò)方法調(diào)用的時(shí)間,所以這不僅不會(huì)提供性能,反而是降低了本該有的性能。

綜合來(lái)看,我們可以對(duì)那些使用頻繁、已經(jīng)確定為終態(tài)的方法、方法體不大的方法用final修飾,提供程序的性能。

優(yōu)先考慮系統(tǒng)中提供的代碼而不是自己寫(xiě)

系統(tǒng)內(nèi)置了許多非常方便的api供我們使用,比如:System、Arrays、Collections、String等內(nèi)置了許多方法api,這比我們自己手寫(xiě)方便多了,除了這個(gè)外,對(duì)于Android來(lái)說(shuō)許多api都使用了底層C/C++實(shí)現(xiàn),所以效率上也比我們自己寫(xiě)快,同樣,對(duì)于系統(tǒng)api,DVM往往也會(huì)使用內(nèi)聯(lián)的方式提高效率

慎用異常

慎用異常并不是不用異常,而是指程序中用拋異常的方式來(lái)執(zhí)行某些操作,比如有些人會(huì)以強(qiáng)拋異常方式來(lái)中斷某些操作等。因?yàn)閽伄惓r(shí)都會(huì)執(zhí)行fillInStackTrace();方法,該方法作用就是重新調(diào)整堆棧,這使得沒(méi)有必要用異常的地方一定要避免使用

責(zé)任編輯:龐桂玉 來(lái)源: 安卓開(kāi)發(fā)精選
相關(guān)推薦

2021-07-29 14:20:34

網(wǎng)絡(luò)優(yōu)化移動(dòng)互聯(lián)網(wǎng)數(shù)據(jù)存儲(chǔ)

2019-12-13 10:25:08

Android性能優(yōu)化啟動(dòng)優(yōu)化

2013-02-20 14:32:37

Android開(kāi)發(fā)性能

2013-09-17 10:32:08

Android性能優(yōu)化數(shù)據(jù)庫(kù)

2017-11-27 12:08:10

后端服務(wù)spring mvc項(xiàng)目

2010-01-28 10:11:18

IT金飯碗

2015-09-16 13:54:30

Android性能優(yōu)化渲染

2015-09-16 15:48:55

Android性能優(yōu)化電量

2015-09-16 14:37:50

Android性能優(yōu)化運(yùn)算

2022-02-16 14:10:51

服務(wù)器性能優(yōu)化Linux

2021-11-29 11:13:45

服務(wù)器網(wǎng)絡(luò)性能

2009-06-30 11:23:02

性能優(yōu)化

2018-01-09 16:56:32

數(shù)據(jù)庫(kù)OracleSQL優(yōu)化

2017-12-23 14:38:41

Android編程開(kāi)發(fā)優(yōu)化

2019-09-25 08:03:21

Android加速Google

2021-07-27 20:51:02

AndroidDNS網(wǎng)絡(luò)

2009-07-17 16:43:02

JRuby性能優(yōu)化

2012-11-28 15:53:16

災(zāi)難恢復(fù)

2011-06-14 14:17:23

性能優(yōu)化系統(tǒng)層次

2021-07-16 23:01:03

SQL索引性能
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)