乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      android開(kāi)發(fā)性能優(yōu)化總結(jié)

       herozhou1314 2012-04-17

      性能優(yōu)化

      Android應(yīng)用程序運(yùn)行的移動(dòng)設(shè)備受限于其運(yùn)算能力,存儲(chǔ)空間,及電池續(xù)航。由此,它必須是高效的。電池續(xù)航可能是一個(gè)促使你優(yōu)化程序的原因,即使他看起來(lái)已經(jīng)運(yùn)行的足夠快了。由于續(xù)航對(duì)用戶的重要性,當(dāng)電量耗損陡增時(shí),意味這用戶遲早會(huì)發(fā)現(xiàn)是由于你的程序。

      雖然這份文檔主要包含著細(xì)微的優(yōu)化,但這些絕不能成為你軟件成敗的關(guān)鍵。選擇合適的算法和數(shù)據(jù)結(jié)構(gòu)永遠(yuǎn)是你最先應(yīng)該考慮的事情,但這超出這份文檔之外。



      簡(jiǎn)介

      寫(xiě)出高效的代碼有兩條基本的原則:

      * 不作沒(méi)有必要的工作。

      * 盡量避免內(nèi)存分配。



      明智的優(yōu)化

      這份文檔是關(guān)于Android規(guī)范的細(xì)微優(yōu)化,所以先確保你已經(jīng)了解哪些代碼需要優(yōu)化,并且知道如何去衡量你所做修改所帶來(lái)的效果(好或壞)。開(kāi)發(fā)投入的時(shí)間是有限的,所以明智的時(shí)間規(guī)劃很重要。

      (更多分析和筆記參見(jiàn)總結(jié)。)

      這份文檔同時(shí)確保你在算法和數(shù)據(jù)結(jié)構(gòu)上作出最佳選擇的同時(shí),考慮API選擇所帶來(lái)的潛在影響。使用合適的數(shù)據(jù)結(jié)構(gòu)和算法比這里的任何建議都更有價(jià)值,優(yōu)先考慮API版本帶來(lái)的影響有助于你找到更好的實(shí)現(xiàn)。(這在類庫(kù)代碼中更為重要,相比應(yīng)用代碼)

      (如果你需要這樣的建議,參見(jiàn) Josh Bloch's Effective Java, item 47.)

      在優(yōu)化Android程序時(shí),會(huì)遇到的一個(gè)棘手問(wèn)題是,保證你的程序能在不同的硬件平臺(tái)上運(yùn)行。虛擬機(jī)版本和處理器各部相同,因此運(yùn)行在之上的速度也大不一樣。但這并且不是簡(jiǎn)單的A比B快或慢,并能在設(shè)備間做出排列。特別的,模擬器上只能評(píng)測(cè)出一小部分設(shè)備上體現(xiàn)的東西。有無(wú)JIT的設(shè)備間也存在著巨大差異,在JIT設(shè)備上好的代碼有時(shí)候會(huì)在無(wú)JIT的設(shè)備上表現(xiàn)的并不好。

      如果你想知道一個(gè)程序在設(shè)備上的具體表現(xiàn),就必須在上面進(jìn)行測(cè)試。



      避免創(chuàng)建不必要的對(duì)象

      對(duì)象創(chuàng)建永遠(yuǎn)不會(huì)是免費(fèi)的。每個(gè)線程的分代GC給零時(shí)對(duì)象分配一個(gè)地址池以降低分配開(kāi)銷,但往往內(nèi)存分配比不分配需要的代價(jià)大。

      如果在用戶界面周期內(nèi)分配對(duì)象,就會(huì)強(qiáng)制一個(gè)周期性的垃圾回收,給用戶體驗(yàn)增加小小的停頓間隙。Gingerbread中提到的并發(fā)回收也許有用,但不必要的工作應(yīng)當(dāng)被避免的。

      因此,應(yīng)該避免不必要的對(duì)象創(chuàng)建。下面是幾個(gè)例子:

      * 如果有一個(gè)返回String的方法,并且他的返回值常常附加在一個(gè)StringBuffer上,改變聲明和實(shí)現(xiàn),讓函數(shù)直接在其后面附加,而非創(chuàng)建一個(gè)短暫存在的零時(shí)變量。

      * 當(dāng)從輸入的數(shù)據(jù)集合中讀取數(shù)據(jù)時(shí),考慮返回原始數(shù)據(jù)的子串,而非新建一個(gè)拷貝.這樣你雖然創(chuàng)建一個(gè)新的對(duì)象,但是他們共享該數(shù)據(jù)的char數(shù)組。(結(jié)果是即使僅僅使用原始輸入的一部分,你也需要保證它的整體一直存在于內(nèi)存中。)

      一個(gè)更徹底的方案是將多維數(shù)組切割成平行一維數(shù)組:

      * Int類型的數(shù)組常有余Integer類型的。推而廣之,兩個(gè)平行的int數(shù)組要比一個(gè)(int,int)型的對(duì)象數(shù)組高效。這對(duì)于其他任何基本數(shù)據(jù)類型的組合都通用。

      * 如果需要實(shí)現(xiàn)一個(gè)容器來(lái)存放元組(Foo,Bar),兩個(gè)平行數(shù)組Foo[],Bar[]會(huì)優(yōu)于一個(gè)(Foo,Bar)對(duì)象的數(shù)組。(例外情況是:當(dāng)你設(shè)計(jì)API給其他代碼調(diào)用時(shí),應(yīng)用好的API設(shè)計(jì)來(lái)?yè)Q取小的速度提升。但在自己的內(nèi)部代碼中,盡量嘗試高效的實(shí)現(xiàn)。)

      通常來(lái)講,盡量避免創(chuàng)建短時(shí)零時(shí)對(duì)象.少的對(duì)象創(chuàng)建意味著低頻的垃圾回收。而這對(duì)于用戶體驗(yàn)產(chǎn)生直接的影響。



      性能之謎

      前一個(gè)版本的文檔給出了好多誤導(dǎo)人的主張,這里做一些澄清:

      在沒(méi)有JIT的設(shè)備上,調(diào)用方法所傳遞的對(duì)象采用具體的類型而非接口類型會(huì)更高效(比如,傳遞HashMap map比Map map調(diào)用一個(gè)方法的開(kāi)銷小,盡管兩個(gè)map都是HashMap).但這并不是兩倍慢的情形,事實(shí)上,他們只相差6%,而有JIT時(shí)這兩種調(diào)用的效率不相上下。

      在沒(méi)有JIT的設(shè)備上,緩存后的字段訪問(wèn)比直接訪問(wèn)快大概20%。而在有JIT的情況下,字段訪問(wèn)的代價(jià)等同于局部訪問(wèn),因此這里不值得優(yōu)化,除非你覺(jué)得他會(huì)讓你的代碼更易讀(對(duì)于final ,static,及static final 變量同樣適用)



      用靜態(tài)代替虛擬

               如果不需要訪問(wèn)某對(duì)象的字段,將方法設(shè)置為靜態(tài),調(diào)用會(huì)加速15%到20%。這也是一種好的做法,因?yàn)槟憧梢詮姆椒暶髦锌闯稣{(diào)用該方法不需要更新此對(duì)象的狀態(tài)。



      避免內(nèi)部的Getters/Setters

      在源生語(yǔ)言像C++中,通常做法是用Getters(i=getCount())代替直接字段訪問(wèn)(i=mCount)。這是C++中一個(gè)好的習(xí)慣,因?yàn)榫幾g器會(huì)內(nèi)聯(lián)這些訪問(wèn),并且如果需要約束或者調(diào)試這些域的訪問(wèn),你可以在任何時(shí)間添加代碼。

      而在Android中,這不是一個(gè)好的做法。虛方法調(diào)用的代價(jià)比直接字段訪問(wèn)高昂許多。通常根據(jù)面向?qū)ο笳Z(yǔ)言的實(shí)踐,在公共接口中使用Getters和Setters是有道理的,但在一個(gè)字段經(jīng)常被訪問(wèn)的類中宜采用直接訪問(wèn)。

      無(wú)JIT時(shí),直接字段訪問(wèn)大約比調(diào)用getter訪問(wèn)快3倍。有JIT時(shí)(直接訪問(wèn)字段開(kāi)銷等同于局部變量訪問(wèn)),要快7倍。在Froyo版本中確實(shí)如此,但以后版本可能會(huì)在JIT中改進(jìn)Getter方法的內(nèi)聯(lián)。



      對(duì)常量使用Static Final修飾符

      考慮下面類首的聲明:


      編譯器會(huì)生成一個(gè)類初始化方法<clinit>,當(dāng)該類初次被使用時(shí)執(zhí)行,這個(gè)方法將42存入intVal中,并得到類文件字符串常量strVal的一個(gè)引用。當(dāng)這些值在后面被引用時(shí),他們通過(guò)字段查找進(jìn)行訪問(wèn)。

      我們改進(jìn)實(shí)現(xiàn),采用 final關(guān)鍵字:


      類不再需要<clinit>方法,因?yàn)槌A客ㄟ^(guò)靜態(tài)字段初始化器進(jìn)入dex文件中。引用intVal的代碼,將直接調(diào)用整形值42;而訪問(wèn)strVal,也會(huì)采用相對(duì)開(kāi)銷較小的“字符串常量”(原文:“sring constant”)指令替代字段查找。(這種優(yōu)化僅僅是針對(duì)基本數(shù)據(jù)類型和String類型常量的,而非任意的引用類型。但盡可能的將常量聲明為static final是一種好的做法。



      使用改進(jìn)的For循環(huán)語(yǔ)法

      改進(jìn)for循環(huán)(有時(shí)被稱為“for-each”循環(huán))能夠用于實(shí)現(xiàn)了iterable接口的集合類及數(shù)組中。在集合類中,迭代器讓接口調(diào)用hasNext()和next()方法。在ArrayList中,手寫(xiě)的計(jì)數(shù)循環(huán)迭代要快3倍(無(wú)論有沒(méi)有JIT),但其他集合類中,改進(jìn)的for循環(huán)語(yǔ)法和迭代器具有相同的效率。

      這里有一些迭代數(shù)組的實(shí)現(xiàn):


      zero()是當(dāng)中最慢的,因?yàn)閷?duì)于這個(gè)遍歷中的歷次迭代,JIT并不能優(yōu)化獲取數(shù)組長(zhǎng)度的開(kāi)銷。

      One()稍快,將所有東西都放進(jìn)局部變量中,避免了查找。但僅只有聲明數(shù)組長(zhǎng)度對(duì)性能改善有益。

      Two()是在無(wú)JIT的設(shè)備上運(yùn)行最快的,對(duì)于有JIT的設(shè)備則和one()不分上下。他采用了JDK1.5中的改進(jìn)for循環(huán)語(yǔ)法。

      結(jié)論:優(yōu)先采用改進(jìn)for循環(huán),但在性能要求苛刻的ArrayList迭代中,考慮采用手寫(xiě)計(jì)數(shù)循環(huán)。

      (參見(jiàn) Effective Java item 46.)



      在私有內(nèi)部?jī)?nèi)中,考慮用包訪問(wèn)權(quán)限替代私有訪問(wèn)權(quán)限

      考慮下面的定義:


      需要注意的關(guān)鍵是:我們定義的一個(gè)私有內(nèi)部類(Foo$Inner),直接訪問(wèn)外部類中的一個(gè)私有方法和私有變量。這是合法的,代碼也會(huì)打印出預(yù)期的“Value is 27”。

      但問(wèn)題是,虛擬機(jī)認(rèn)為從Foo$Inner中直接訪問(wèn)Foo的私有成員是非法的,因?yàn)樗麄兪莾蓚€(gè)不同的類,盡管Java語(yǔ)言允許內(nèi)部類訪問(wèn)外部類的私有成員,但是通過(guò)編譯器生成幾個(gè)綜合方法來(lái)橋接這些間隙的。


      內(nèi)部類會(huì)在外部類中任何需要訪問(wèn)mValue字段或調(diào)用doStuff方法的地方調(diào)用這些靜態(tài)方法。這意味著這些代碼將直接存取成員變量表現(xiàn)為通過(guò)存取器方法訪問(wèn)。之前提到過(guò)存取器訪問(wèn)如何比直接訪問(wèn)慢,這例子說(shuō)明,某些語(yǔ)言約會(huì)定導(dǎo)致不可見(jiàn)的性能問(wèn)題。

      如果你在高性能的Hotspot中使用這些代碼,可以通過(guò)聲明被內(nèi)部類訪問(wèn)的字段和成員為包訪問(wèn)權(quán)限,而非私有。但這也意味著這些字段會(huì)被其他處于同一個(gè)包中的類訪問(wèn),因此在公共API中不宜采用。



      合理利用浮點(diǎn)數(shù)

      通常的經(jīng)驗(yàn)是,在Android設(shè)備中,浮點(diǎn)數(shù)會(huì)比整型慢兩倍,在缺少FPU和JIT的G1上對(duì)比有FPU和JIT的Nexus One中確實(shí)如此(兩種設(shè)備間算術(shù)運(yùn)算的絕對(duì)速度差大約是10倍)

      從速度方面說(shuō),在現(xiàn)代硬件上,float和double之間沒(méi)有任何不同。更廣泛的講,double大2倍。在臺(tái)式機(jī)上,由于不存在空間問(wèn)題,double的優(yōu)先級(jí)高于float。

      但即使是整型,有的芯片擁有硬件乘法,卻缺少除法。這種情況下,整型除法和求模運(yùn)算是通過(guò)軟件實(shí)現(xiàn)的,就像當(dāng)你設(shè)計(jì)Hash表,或是做大量的算術(shù)那樣。



      了解并使用類庫(kù)

               選擇Library中的代碼而非自己重寫(xiě),除了通常的那些原因外,考慮到系統(tǒng)空閑時(shí)會(huì)用匯編代碼調(diào)用來(lái)替代library方法,這可能比JIT中生成的等價(jià)的最好的Java代碼還要好。典型的例子就是String.indexOf,Dalvik用內(nèi)部?jī)?nèi)聯(lián)來(lái)替代。同樣的,System.arraycopy方法在有JIT的Nexus One上,自行編碼的循環(huán)快9倍。

               (參見(jiàn) Effective Java item 47.)



      合理利用本地方法

      本地方法并不是一定比Java高效。最起碼,Java和native之間過(guò)渡的關(guān)聯(lián)是有消耗的,而JIT并不能對(duì)此進(jìn)行優(yōu)化。當(dāng)你分配本地資源時(shí)(本地堆上的內(nèi)存,文件說(shuō)明符等),往往很難實(shí)時(shí)的回收這些資源。同時(shí)你也需要在各種結(jié)構(gòu)中編譯你的代碼(而非依賴JIT)。甚至可能需要針對(duì)相同的架構(gòu)來(lái)編譯出不同的版本:針對(duì)ARM處理器的GI編譯的本地代碼,并不能充分利用Nexus One上的ARM,而針對(duì)Nexus One上ARM編譯的本地代碼不能在G1的ARM上運(yùn)行。

      當(dāng)你想部署程序到存在本地代碼庫(kù)的Android平臺(tái)上時(shí),本地代碼才顯得尤為有用,而并非為了Java應(yīng)用程序的提速。

      (參見(jiàn) Effective Java item 54.)



      結(jié)語(yǔ)

      最后:通??紤]的是:先確定存在問(wèn)題,再進(jìn)行優(yōu)化。并且你知道當(dāng)前系統(tǒng)的性能,否則無(wú)法衡量你進(jìn)行嘗試所得到的提升。

      這份文檔中的每個(gè)主張都有標(biāo)準(zhǔn)基準(zhǔn)測(cè)試作為支持。你可以在code.google.com“dalvik”項(xiàng)目中找到基準(zhǔn)測(cè)試的代碼。

      這個(gè)標(biāo)準(zhǔn)基準(zhǔn)測(cè)試是建立在Caliper Java標(biāo)準(zhǔn)微基準(zhǔn)測(cè)試框架之上的。標(biāo)準(zhǔn)微基準(zhǔn)測(cè)試很難找到正確的路,所以Caliper幫你完成了其中的困難部分工作。并且當(dāng)你會(huì)察覺(jué)到某些情況的測(cè)試結(jié)果并想象中的那樣(虛擬機(jī)總是在優(yōu)化你的代碼的)。我們強(qiáng)烈推薦你用Caliper來(lái)運(yùn)行你自己的標(biāo)準(zhǔn)微基準(zhǔn)測(cè)試。

      同時(shí)你也會(huì)發(fā)現(xiàn)Traceview對(duì)分析很有用,但必須了解,他目前是不不支持JIT的,這可能導(dǎo)致那些在JIT上可以勝出的代碼運(yùn)行超時(shí)。特別重要的,根據(jù)Taceview的數(shù)據(jù)作出更改后,請(qǐng)確保代碼在沒(méi)有Traceview時(shí),確實(shí)跑的快了。

       

      (轉(zhuǎn)載請(qǐng)注明出處:[url=http://www.]博彩通[/url][url=http://www.]e世博[/url]

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多