自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android Training - 管理應(yīng)用的內(nèi)存

移動(dòng)開(kāi)發(fā) Android
為了GC能夠從app中及時(shí)回收內(nèi)存,我們需要注意避免內(nèi)存泄露(通常由于在全局成員變量中持有對(duì)象引用而導(dǎo)致)并且在適當(dāng)?shù)臅r(shí)機(jī)(下面會(huì)講到的lifecycle callbacks)來(lái)釋放引用對(duì)象。對(duì)于大多數(shù)app來(lái)說(shuō),Dalvik的GC會(huì)自動(dòng)把離開(kāi)活動(dòng)線程的對(duì)象進(jìn)行回收。

Random Access Memory(RAM)在任何軟件開(kāi)發(fā)環(huán)境中都是一個(gè)很寶貴的資源。這一點(diǎn)在物理內(nèi)存通常很有限的移動(dòng)操作系統(tǒng)上,顯得尤為突出。盡管Android的Dalvik虛擬機(jī)扮演了常規(guī)的垃圾回收的角色,但這并不意味著你可以忽視app的內(nèi)存分配與釋放的時(shí)機(jī)與地點(diǎn)。

為了GC能夠從app中及時(shí)回收內(nèi)存,我們需要注意避免內(nèi)存泄露(通常由于在全局成員變量中持有對(duì)象引用而導(dǎo)致)并且在適當(dāng)?shù)臅r(shí)機(jī)(下面會(huì)講到的lifecycle callbacks)來(lái)釋放引用對(duì)象。對(duì)于大多數(shù)app來(lái)說(shuō),Dalvik的GC會(huì)自動(dòng)把離開(kāi)活動(dòng)線程的對(duì)象進(jìn)行回收。

這篇文章會(huì)解釋Android是如何管理app的進(jìn)程與內(nèi)存分配,以及在開(kāi)發(fā)Android應(yīng)用的時(shí)候如何主動(dòng)的減少內(nèi)存的使用。關(guān)于Java的資源管理機(jī)制,請(qǐng)參考其它書(shū)籍或者線上材料。如果你正在尋找如何分析你的內(nèi)存使用情況的文章,請(qǐng)參考這里Investigating Your RAM Usage。
第1部分: Android是如何管理內(nèi)存的

Android并沒(méi)有為內(nèi)存提供交換區(qū)(Swap space),但是它有使用paging與memory-mapping(mmapping)的機(jī)制來(lái)管理內(nèi)存。這意味著任何你修改的內(nèi)存(無(wú)論是通過(guò)分配新的對(duì)象還是去訪問(wèn)mmaped pages中的內(nèi)容)都會(huì)貯存在RAM中,而且不能被paged out。因此唯一完整釋放內(nèi)存的方法是釋放那些你可能hold住的對(duì)象的引用,當(dāng)這個(gè)對(duì)象沒(méi)有被任何其他對(duì)象所引用的時(shí)候,它就能夠被GC回收了。只有一種例外是:如果系統(tǒng)想要在其他地方重用這個(gè)對(duì)象。
1) 共享內(nèi)存

Android通過(guò)下面幾個(gè)方式在不同的進(jìn)程中來(lái)實(shí)現(xiàn)共享RAM:

每一個(gè)app的進(jìn)程都是從一個(gè)被叫做Zygote的進(jìn)程中fork出來(lái)的。Zygote進(jìn)程在系統(tǒng)啟動(dòng)并且載入通用的framework的代碼與資源之后開(kāi)始啟動(dòng)。為了啟動(dòng)一個(gè)新的程序進(jìn)程,系統(tǒng)會(huì)fork Zygote進(jìn)程生成一個(gè)新的進(jìn)程,然后在新的進(jìn)程中加載并運(yùn)行app的代碼。這使得大多數(shù)的RAM pages被用來(lái)分配給framework的代碼,同時(shí)使得RAM資源能夠在應(yīng)用的所有進(jìn)程中進(jìn)行共享。

大多數(shù)static的數(shù)據(jù)被mmapped到一個(gè)進(jìn)程中。這不僅僅使得同樣的數(shù)據(jù)能夠在進(jìn)程間進(jìn)行共享,而且使得它能夠在需要的時(shí)候被paged out。例如下面幾種static的數(shù)據(jù):
Dalvik 代碼 (放在一個(gè)預(yù)鏈接好的 .odex 文件中以便直接mapping)
App resources (通過(guò)把資源表結(jié)構(gòu)設(shè)計(jì)成便于mmapping的數(shù)據(jù)結(jié)構(gòu),另外還可以通過(guò)把APK中的文件做aligning的操作來(lái)優(yōu)化)
傳統(tǒng)項(xiàng)目元素,比如 .so 文件中的本地代碼.
在很多情況下,Android通過(guò)顯式的分配共享內(nèi)存區(qū)域(例如ashmem或者gralloc)來(lái)實(shí)現(xiàn)一些動(dòng)態(tài)RAM區(qū)域能夠在不同進(jìn)程間進(jìn)行共享。例如,window surfaces在app與screen compositor之間使用共享的內(nèi)存,cursor buffers在content provider與client之間使用共享的內(nèi)存。

關(guān)于如何查看app所使用的共享內(nèi)存,請(qǐng)查看Investigating Your RAM Usage
2) 分配與回收內(nèi)存

這里有下面幾點(diǎn)關(guān)于Android如何分配與回收內(nèi)存的事實(shí):

每一個(gè)進(jìn)程的Dalvik heap都有一個(gè)受限的虛擬內(nèi)存范圍。這就是邏輯上講的heap size,它可以隨著需要進(jìn)行增長(zhǎng),但是會(huì)有一個(gè)系統(tǒng)為它所定義的上限。
邏輯上講的heap size和實(shí)際物理上使用的內(nèi)存數(shù)量是不等的,Android會(huì)計(jì)算一個(gè)叫做Proportional Set Size(PSS)的值,它記錄了那些和其他進(jìn)程進(jìn)行共享的內(nèi)存大小。(假設(shè)共享內(nèi)存大小是10M,一共有20個(gè)Process在共享使用,根據(jù)權(quán)重,可能認(rèn)為其中有0.3M才能真正算是你的進(jìn)程所使用的)
Dalvik heap與邏輯上的heap size不吻合,這意味著Android并不會(huì)去做heap中的碎片整理用來(lái)關(guān)閉空閑區(qū)域。Android僅僅會(huì)在heap的尾端出現(xiàn)不使用的空間時(shí)才會(huì)做收縮邏輯heap size大小的動(dòng)作。但是這并不是意味著被heap所使用的物理內(nèi)存大小不能被收縮。在垃圾回收之后,Dalvik會(huì)遍歷heap并找出不使用的pages,然后使用madvise(系統(tǒng)調(diào)用)把那些pages返回給kernal。因此,成對(duì)的allocations與deallocations大塊的數(shù)據(jù)可以使得物理內(nèi)存能夠被正常的回收。然而,回收碎片化的內(nèi)存則會(huì)使得效率低下很多,因?yàn)槟切┧槠姆峙漤?yè)面也許會(huì)被其他地方所共享到。

3) 限制應(yīng)用的內(nèi)存

為了維持多任務(wù)的功能環(huán)境,Android為每一個(gè)app都設(shè)置了一個(gè)硬性的heap size限制。準(zhǔn)確的heap size限制會(huì)因?yàn)椴煌O(shè)備的不同RAM大小而各有差異。如果你的app已經(jīng)到了heap的限制大小并且再?lài)L試分配內(nèi)存的話(huà),會(huì)引起OutOfMemoryError的錯(cuò)誤。

在一些情況下,你也許想要查詢(xún)當(dāng)前設(shè)備的heap size限制大小是多少,然后決定cache的大小??梢酝ㄟ^(guò)getMemoryClass()來(lái)查詢(xún)。這個(gè)方法會(huì)返回一個(gè)整數(shù),表明你的應(yīng)用的heap size限制是多少M(fèi)b(megabates)。
4) 切換應(yīng)用

Android并不會(huì)在用戶(hù)切換不同應(yīng)用時(shí)候做交換內(nèi)存的操作。Android會(huì)把那些不包含foreground組件的進(jìn)程放到LRU cache中。例如,當(dāng)用戶(hù)剛開(kāi)始啟動(dòng)了一個(gè)應(yīng)用,系統(tǒng)會(huì)為它創(chuàng)建了一個(gè)進(jìn)程,但是當(dāng)用戶(hù)離開(kāi)這個(gè)應(yīng)用,此進(jìn)程并不會(huì)立即被銷(xiāo)毀。系統(tǒng)會(huì)把這個(gè)進(jìn)程放到cache中,如果用戶(hù)后來(lái)再回到這個(gè)應(yīng)用,此進(jìn)程就能夠被完整恢復(fù),從而實(shí)現(xiàn)應(yīng)用的快速切換。

如果你的應(yīng)用中有一個(gè)被緩存的進(jìn)程,這個(gè)進(jìn)程會(huì)占用暫時(shí)不需要使用到的內(nèi)存,這個(gè)暫時(shí)不需要使用的進(jìn)程,它被保留在內(nèi)存中,這會(huì)對(duì)系統(tǒng)的整體性能有影響。因此當(dāng)系統(tǒng)開(kāi)始進(jìn)入低內(nèi)存狀態(tài)時(shí),它會(huì)由系統(tǒng)根據(jù)LRU的規(guī)則與其他因素選擇綜合考慮之后決定殺掉某些進(jìn)程,為了保持你的進(jìn)程能夠盡可能長(zhǎng)久的被緩存,請(qǐng)參考下面的章節(jié)學(xué)習(xí)何時(shí)釋放你的引用。

對(duì)于那些不在foreground的進(jìn)程,Android是如何決定kill掉哪一類(lèi)進(jìn)程的問(wèn)題,請(qǐng)參考Processes and Threads.
第2部分: 你的應(yīng)用該如何管理內(nèi)存

你應(yīng)該在開(kāi)發(fā)過(guò)程的每一個(gè)階段都考慮到RAM的有限性,甚至包括在開(kāi)始編寫(xiě)代碼之前的設(shè)計(jì)階段就應(yīng)該考慮到RAM的限制性。我們可以使用多種設(shè)計(jì)與實(shí)現(xiàn)方式,他們有著不同的效率,即使這些方式只是相同技術(shù)的不斷組合與演變。

為了使得你的應(yīng)用性能效率更高,你應(yīng)該在設(shè)計(jì)與實(shí)現(xiàn)代碼時(shí),遵循下面的技術(shù)要點(diǎn)。
1) 珍惜Services資源

如果你的應(yīng)用需要在后臺(tái)使用service,除非它被觸發(fā)并執(zhí)行一個(gè)任務(wù),否則其他時(shí)候service都應(yīng)該是停止?fàn)顟B(tài)。另外需要注意當(dāng)這個(gè)service完成任務(wù)之后因?yàn)橥V箂ervice失敗而引起的內(nèi)存泄漏。

當(dāng)你啟動(dòng)一個(gè)service,系統(tǒng)會(huì)傾向?yàn)榱吮A暨@個(gè)service而一直保留service所在的進(jìn)程。這使得進(jìn)程的運(yùn)行代價(jià)很高,因?yàn)橄到y(tǒng)沒(méi)有辦法把service所占用的RAM空間騰出來(lái)讓給其他組件,另外service還不能被paged out。這減少了系統(tǒng)能夠存放到LRU緩存當(dāng)中的進(jìn)程數(shù)量,它會(huì)影響app之間的切換效率。它甚至?xí)?dǎo)致系統(tǒng)內(nèi)存使用不穩(wěn)定,從而無(wú)法繼續(xù)保持住所有目前正在運(yùn)行的service。

限制你的service的***辦法是使用IntentService, 它會(huì)在處理完交代給它的intent任務(wù)之后盡快結(jié)束自己。更多信息,請(qǐng)閱讀Running in a Background Service.

當(dāng)一個(gè)Service已經(jīng)不再需要的時(shí)候還繼續(xù)保留它,這對(duì)Android應(yīng)用的內(nèi)存管理來(lái)說(shuō)是最糟糕的錯(cuò)誤之一。因此千萬(wàn)不要貪婪的使得一個(gè)Service持續(xù)保留。不僅僅是因?yàn)樗鼤?huì)使得你的應(yīng)用因?yàn)镽AM空間的不足而性能糟糕,還會(huì)使得用戶(hù)發(fā)現(xiàn)那些有著常駐后臺(tái)行為的應(yīng)用并且可能卸載它。
2) 當(dāng)UI隱藏時(shí)釋放內(nèi)存

當(dāng)用戶(hù)切換到其它應(yīng)用并且你的應(yīng)用 UI不再可見(jiàn)時(shí),你應(yīng)該釋放你的應(yīng)用UI上所占用的所有內(nèi)存資源。在這個(gè)時(shí)候釋放UI資源可以顯著的增加系統(tǒng)緩存進(jìn)程的能力,它會(huì)對(duì)用戶(hù)體驗(yàn)有著很直接的影響。

為了能夠接收到用戶(hù)離開(kāi)你的UI時(shí)的通知,你需要實(shí)現(xiàn)Activtiy類(lèi)里面的onTrimMemory()回調(diào)方法。你應(yīng)該使用這個(gè)方法來(lái)監(jiān)聽(tīng)到TRIM_MEMORY_UI_HIDDEN級(jí)別的回調(diào),此時(shí)意味著你的UI已經(jīng)隱藏,你應(yīng)該釋放那些僅僅被你的UI使用的資源。

請(qǐng)注意:你的應(yīng)用僅僅會(huì)在所有UI組件的被隱藏的時(shí)候接收到onTrimMemory()的回調(diào)并帶有參數(shù)TRIM_MEMORY_UI_HIDDEN。這與onStop()的回調(diào)是不同的,onStop會(huì)在activity的實(shí)例隱藏時(shí)會(huì)執(zhí)行,例如當(dāng)用戶(hù)從你的app的某個(gè)activity跳轉(zhuǎn)到另外一個(gè)activity時(shí)前面activity的onStop()會(huì)被執(zhí)行。因此你應(yīng)該實(shí)現(xiàn)onStop回調(diào),并且在此回調(diào)里面釋放activity的資源,例如釋放網(wǎng)絡(luò)連接,注銷(xiāo)監(jiān)聽(tīng)廣播接收者。除非接收到onTrimMemory(TRIM_MEMORY_UI_HIDDEN))的回調(diào),否者你不應(yīng)該釋放你的UI資源。這確保了用戶(hù)從其他activity切回來(lái)時(shí),你的UI資源仍然可用,并且可以迅速恢復(fù)activity。
3) 當(dāng)內(nèi)存緊張時(shí)釋放部分內(nèi)存

在你的app生命周期的任何階段,onTrimMemory的回調(diào)方法同樣可以告訴你整個(gè)設(shè)備的內(nèi)存資源已經(jīng)開(kāi)始緊張。你應(yīng)該根據(jù)onTrimMemory回調(diào)中的內(nèi)存級(jí)別來(lái)進(jìn)一步?jīng)Q定釋放哪些資源。

TRIM_MEMORY_RUNNING_MODERATE:你的app正在運(yùn)行并且不會(huì)被列為可殺死的。但是設(shè)備此時(shí)正運(yùn)行于低內(nèi)存狀態(tài)下,系統(tǒng)開(kāi)始觸發(fā)殺死LRU Cache中的Process的機(jī)制。
TRIM_MEMORY_RUNNING_LOW:你的app正在運(yùn)行且沒(méi)有被列為可殺死的。但是設(shè)備正運(yùn)行于更低內(nèi)存的狀態(tài)下,你應(yīng)該釋放不用的資源用來(lái)提升系統(tǒng)性能(但是這也會(huì)直接影響到你的app的性能)。
TRIM_MEMORY_RUNNING_CRITICAL:你的app仍在運(yùn)行,但是系統(tǒng)已經(jīng)把LRU Cache中的大多數(shù)進(jìn)程都已經(jīng)殺死,因此你應(yīng)該立即釋放所有非必須的資源。如果系統(tǒng)不能回收到足夠的RAM數(shù)量,系統(tǒng)將會(huì)清除所有的LRU緩存中的進(jìn)程,并且開(kāi)始?xì)⑺滥切┲氨徽J(rèn)為不應(yīng)該殺死的進(jìn)程,例如那個(gè)包含了一個(gè)運(yùn)行態(tài)Service的進(jìn)程。

同樣,當(dāng)你的app進(jìn)程正在被cached時(shí),你可能會(huì)接受到從onTrimMemory()中返回的下面的值之一:

TRIM_MEMORY_BACKGROUND: 系統(tǒng)正運(yùn)行于低內(nèi)存狀態(tài)并且你的進(jìn)程正處于LRU緩存名單中最不容易殺掉的位置。盡管你的app進(jìn)程并不是處于被殺掉的高危險(xiǎn)狀態(tài),系統(tǒng)可能已經(jīng)開(kāi)始?xì)⒌鬖RU緩存中的其他進(jìn)程了。你應(yīng)該釋放那些容易恢復(fù)的資源,以便于你的進(jìn)程可以保留下來(lái),這樣當(dāng)用戶(hù)回退到你的app的時(shí)候才能夠迅速恢復(fù)。
TRIM_MEMORY_MODERATE: 系統(tǒng)正運(yùn)行于低內(nèi)存狀態(tài)并且你的進(jìn)程已經(jīng)已經(jīng)接近LRU名單的中部位置。如果系統(tǒng)開(kāi)始變得更加內(nèi)存緊張,你的進(jìn)程是有可能被殺死的。
TRIM_MEMORY_COMPLETE: 系統(tǒng)正運(yùn)行與低內(nèi)存的狀態(tài)并且你的進(jìn)程正處于LRU名單中最容易被殺掉的位置。你應(yīng)該釋放任何不影響你的app恢復(fù)狀態(tài)的資源。

因?yàn)閛nTrimMemory()的回調(diào)是在API 14才被加進(jìn)來(lái)的,對(duì)于老的版本,你可以使用onLowMemory)回調(diào)來(lái)進(jìn)行兼容。onLowMemory相當(dāng)與TRIM_MEMORY_COMPLETE。

Note: 當(dāng)系統(tǒng)開(kāi)始清除LRU緩存中的進(jìn)程時(shí),盡管它首先按照LRU的順序來(lái)操作,但是它同樣會(huì)考慮進(jìn)程的內(nèi)存使用量。因此消耗越少的進(jìn)程則越容易被留下來(lái)。

4) 檢查你應(yīng)該使用多少的內(nèi)存

正如前面提到的,每一個(gè)Android設(shè)備都會(huì)有不同的RAM總大小與可用空間,因此不同設(shè)備為app提供了不同大小的heap限制。你可以通過(guò)調(diào)用getMemoryClass())來(lái)獲取你的app的可用heap大小。如果你的app嘗試申請(qǐng)更多的內(nèi)存,會(huì)出現(xiàn)OutOfMemory的錯(cuò)誤。

在一些特殊的情景下,你可以通過(guò)在manifest的application標(biāo)簽下添加largeHeap=true的屬性來(lái)聲明一個(gè)更大的heap空間。如果你這樣做,你可以通過(guò)getLargeMemoryClass())來(lái)獲取到一個(gè)更大的heap size。

然而,能夠獲取更大heap的設(shè)計(jì)本意是為了一小部分會(huì)消耗大量RAM的應(yīng)用(例如一個(gè)大圖片的編輯應(yīng)用)。不要輕易的因?yàn)槟阈枰褂么罅康膬?nèi)存而去請(qǐng)求一個(gè)大的heap size。只有當(dāng)你清楚的知道哪里會(huì)使用大量的內(nèi)存并且為什么這些內(nèi)存必須被保留時(shí)才去使用large heap. 因此請(qǐng)盡量少使用large heap。使用額外的內(nèi)存會(huì)影響系統(tǒng)整體的用戶(hù)體驗(yàn),并且會(huì)使得GC的每次運(yùn)行時(shí)間更長(zhǎng)。在任務(wù)切換時(shí),系統(tǒng)的性能會(huì)變得大打折扣。

另外, large heap并不一定能夠獲取到更大的heap。在某些有嚴(yán)格限制的機(jī)器上,large heap的大小和通常的heap size是一樣的。因此即使你申請(qǐng)了large heap,你還是應(yīng)該通過(guò)執(zhí)行g(shù)etMemoryClass()來(lái)檢查實(shí)際獲取到的heap大小。
5) 避免bitmaps的浪費(fèi)

當(dāng)你加載一個(gè)bitmap時(shí),僅僅需要保留適配當(dāng)前屏幕設(shè)備分辨率的數(shù)據(jù)即可,如果原圖高于你的設(shè)備分辨率,需要做縮小的動(dòng)作。請(qǐng)記住,增加bitmap的尺寸會(huì)對(duì)內(nèi)存呈現(xiàn)出2次方的增加,因?yàn)閄與Y都在增加。

Note:在Android 2.3.x (API level 10)及其以下, bitmap對(duì)象的pixel data是存放在native內(nèi)存中的,它不便于調(diào)試。然而,從Android 3.0(API level 11)開(kāi)始,bitmap pixel data是分配在你的app的Dalvik heap中, 這提升了GC的工作效率并且更加容易Debug。因此如果你的app使用bitmap并在舊的機(jī)器上引發(fā)了一些內(nèi)存問(wèn)題,切換到3.0以上的機(jī)器上進(jìn)行Debug。

6) 使用優(yōu)化的數(shù)據(jù)容器

利用Android Framework里面優(yōu)化過(guò)的容器類(lèi),例如SparseArray, SparseBooleanArray, 與 LongSparseArray。 通常的HashMap的實(shí)現(xiàn)方式更加消耗內(nèi)存,因?yàn)樗枰粋€(gè)額外的實(shí)例對(duì)象來(lái)記錄Mapping操作。另外,SparseArray更加高效在于他們避免了對(duì)key與value的autobox自動(dòng)裝箱,并且避免了裝箱后的解箱。
7) 請(qǐng)注意內(nèi)存開(kāi)銷(xiāo)

對(duì)你所使用的語(yǔ)言與庫(kù)的成本與開(kāi)銷(xiāo)有所了解,從開(kāi)始到結(jié)束,在設(shè)計(jì)你的app時(shí)謹(jǐn)記這些信息。通常,表面上看起來(lái)無(wú)關(guān)痛癢(innocuous)的事情也許實(shí)際上會(huì)導(dǎo)致大量的開(kāi)銷(xiāo)。例如:

Enums的內(nèi)存消耗通常是static constants的2倍。你應(yīng)該盡量避免在Android上使用enums。
在Java中的每一個(gè)類(lèi)(包括匿名內(nèi)部類(lèi))都會(huì)使用大概500 bytes。
每一個(gè)類(lèi)的實(shí)例花銷(xiāo)是12-16 bytes。
往HashMap添加一個(gè)entry需要額一個(gè)額外占用的32 bytes的entry對(duì)象。

8) 請(qǐng)注意代碼“抽象”

通常,開(kāi)發(fā)者使用抽象作為”好的編程實(shí)踐”,因?yàn)槌橄竽軌蛱嵘a的靈活性與可維護(hù)性。然而,抽象會(huì)導(dǎo)致一個(gè)顯著的開(kāi)銷(xiāo):通常他們需要同等量的代碼用于可執(zhí)行。那些代碼會(huì)被map到內(nèi)存中。因此如果你的抽象沒(méi)有顯著的提升效率,應(yīng)該盡量避免他們。
9) 為序列化的數(shù)據(jù)使用nano protobufs

Protocol buffers是由Google為序列化結(jié)構(gòu)數(shù)據(jù)而設(shè)計(jì)的,一種語(yǔ)言無(wú)關(guān),平臺(tái)無(wú)關(guān),具有良好擴(kuò)展性的協(xié)議。類(lèi)似XML,卻比XML更加輕量,快速,簡(jiǎn)單。如果你需要為你的數(shù)據(jù)實(shí)現(xiàn)協(xié)議化,你應(yīng)該在客戶(hù)端的代碼中總是使用nano protobufs。通常的協(xié)議化操作會(huì)生成大量繁瑣的代碼,這容易給你的app帶來(lái)許多問(wèn)題:增加RAM的使用量,顯著增加APK的大小,更慢的執(zhí)行速度,更容易達(dá)到DEX的字符限制。

關(guān)于更多細(xì)節(jié),請(qǐng)參考protobuf readme的”Nano version”章節(jié)。
10) 避免使用依賴(lài)注入框架

使用類(lèi)似Guice或者RoboGuice等f(wàn)ramework injection包是很有效的,因?yàn)樗麄兡軌蚝?jiǎn)化你的代碼。

Notes:RoboGuice 2 通過(guò)依賴(lài)注入改變代碼風(fēng)格,讓Android開(kāi)發(fā)時(shí)的體驗(yàn)更好。你在調(diào)用 getIntent().getExtras() 時(shí)經(jīng)常忘記檢查 null 嗎?RoboGuice 2 可以幫你做。你認(rèn)為將 findViewById() 的返回值強(qiáng)制轉(zhuǎn)換成 TextView 是本不必要的工作嗎? RoboGuice 2 可以幫你。RoboGuice 把這些需要猜測(cè)性的工作移到Android開(kāi)發(fā)以外去了。RoboGuice 2 會(huì)負(fù)責(zé)注入你的 View, Resource, System Service或者其他對(duì)象等等類(lèi)似的細(xì)節(jié)。

然而,那些框架會(huì)通過(guò)掃描你的代碼執(zhí)行許多初始化的操作,這會(huì)導(dǎo)致你的代碼需要大量的RAM來(lái)mapping代碼,而且mapped pages會(huì)長(zhǎng)時(shí)間的被保留在RAM中。
11) 謹(jǐn)慎使用第三方libraries

很多開(kāi)源的library代碼都不是為移動(dòng)網(wǎng)絡(luò)環(huán)境而編寫(xiě)的,如果運(yùn)用在移動(dòng)設(shè)備上,,這樣的效率并不高。當(dāng)你決定使用一個(gè)第三方library的時(shí)候,你應(yīng)該針對(duì)移動(dòng)網(wǎng)絡(luò)做繁瑣的遷移與維護(hù)的工作。

即使是針對(duì)Android而設(shè)計(jì)的library,也可能是很危險(xiǎn)的,因?yàn)槊恳粋€(gè)library所做的事情都是不一樣的。例如,其中一個(gè)lib使用的是nano protobufs, 而另外一個(gè)使用的是micro protobufs。那么這樣,在你的app里面就有2種protobuf的實(shí)現(xiàn)方式。這樣的沖突同樣可能發(fā)生在輸出日志,加載圖片,緩存等等模塊里面。

同樣不要陷入為了1個(gè)或者2個(gè)功能而導(dǎo)入整個(gè)library的陷阱。如果沒(méi)有一個(gè)合適的庫(kù)與你的需求相吻合,你應(yīng)該考慮自己去實(shí)現(xiàn),而不是導(dǎo)入一個(gè)大而全的解決方案。
12) 優(yōu)化整體性能

官方有列出許多優(yōu)化整個(gè)app性能的文章:Best Practices for Performance。這篇文章就是其中之一。有些文章是講解如何優(yōu)化app的CPU使用效率,有些是如何優(yōu)化app的內(nèi)存使用效率。

你還應(yīng)該閱讀optimizing your UI來(lái)為layout進(jìn)行優(yōu)化。同樣還應(yīng)該關(guān)注lint工具所提出的建議,進(jìn)行優(yōu)化。
13) 使用ProGuard來(lái)剔除不需要的代碼

ProGuard能夠通過(guò)移除不需要的代碼,重命名類(lèi),域與方法等方對(duì)代碼進(jìn)行壓縮,優(yōu)化與混淆。使用ProGuard可以使得你的代碼更加緊湊,這樣能夠使用更少mapped代碼所需要的RAM。
14) 對(duì)最終的APK使用zipalign

在編寫(xiě)完所有代碼,并通過(guò)編譯系統(tǒng)生成APK之后,你需要使用zipalign對(duì)APK進(jìn)行重新校準(zhǔn)。如果你不做這個(gè)步驟,會(huì)導(dǎo)致你的APK需要更多的RAM,因?yàn)橐恍╊?lèi)似圖片資源的東西不能被mapped。

Notes: Google Play不接受沒(méi)有經(jīng)過(guò)zipalign的APK。

15) 分析你的RAM使用情況

一旦你獲取到一個(gè)相對(duì)穩(wěn)定的版本后,需要分析你的app整個(gè)生命周期內(nèi)使用的內(nèi)存情況,并進(jìn)行優(yōu)化,更多細(xì)節(jié)請(qǐng)參考Investigating Your RAM Usage.
16) 使用多進(jìn)程

如果合適的話(huà),有一個(gè)更高級(jí)的技術(shù)可以幫助你的app管理內(nèi)存使用:通過(guò)把你的app組件切分成多個(gè)組件,運(yùn)行在不同的進(jìn)程中。這個(gè)技術(shù)必須謹(jǐn)慎使用,大多數(shù)app都不應(yīng)該運(yùn)行在多個(gè)進(jìn)程中。因?yàn)槿绻褂貌划?dāng),它會(huì)顯著增加內(nèi)存的使用,而不是減少。當(dāng)你的app需要在后臺(tái)運(yùn)行與前臺(tái)一樣的大量的任務(wù)的時(shí)候,可以考慮使用這個(gè)技術(shù)。

一個(gè)典型的例子是創(chuàng)建一個(gè)可以長(zhǎng)時(shí)間后臺(tái)播放的Music Player。如果整個(gè)app運(yùn)行在一個(gè)進(jìn)程中,當(dāng)后臺(tái)播放的時(shí)候,前臺(tái)的那些UI資源也沒(méi)有辦法得到釋放。類(lèi)似這樣的app可以切分成2個(gè)進(jìn)程:一個(gè)用來(lái)操作UI,另外一個(gè)用來(lái)后臺(tái)的Service.

你可以通過(guò)在manifest文件中聲明’android:process’屬性來(lái)實(shí)現(xiàn)某個(gè)組件運(yùn)行在另外一個(gè)進(jìn)程的操作。

 

 

  1. <service android:name=".PlaybackService" 
  2. android:process=":background" /> 

 

責(zé)任編輯:chenqingxiang 來(lái)源: 胡凱的博客
相關(guān)推薦

2022-01-04 13:54:57

應(yīng)用程序IT監(jiān)測(cè)

2011-09-07 15:52:01

EverNote筆記管理

2009-06-17 14:43:47

Spring框架Spring事務(wù)管理

2012-02-23 11:02:06

惠普iOSAndroid

2023-10-09 08:14:10

Helm管理應(yīng)用

2022-01-10 09:35:50

日志語(yǔ)言解析器

2010-02-05 13:52:04

C++資源管理

2012-06-07 09:15:14

ibmdw

2012-02-16 08:57:14

服務(wù)器管理應(yīng)用系統(tǒng)管理員

2023-05-04 07:37:44

KDEArianna

2021-08-17 10:43:57

WindowsiCloud更新

2010-03-16 19:59:32

上網(wǎng)行為管理網(wǎng)橋深信服科技

2009-03-04 06:28:00

windows2008服務(wù)器管理Windows服務(wù)器配

2009-09-29 14:20:05

OSGiContactDAO

2019-02-27 11:10:29

時(shí)間管理軟件應(yīng)用

2017-08-17 10:03:06

磁盤(pán)系統(tǒng)實(shí)例

2011-09-16 16:31:21

iPhone應(yīng)用Groove資源管理

2014-07-21 14:40:43

Android內(nèi)存

2014-07-28 15:01:56

Android內(nèi)存

2010-07-16 10:56:16

點(diǎn)贊
收藏

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