android性能優(yōu)化(一)內(nèi)存管理

? ? ? ? Android的內(nèi)存優(yōu)化是性能優(yōu)化中很重要的一部分袄膏,而避免OOM又是內(nèi)存優(yōu)化中比較核心的一點(diǎn)乱投。本文是個(gè)人工作中的總結(jié)和參考了一些其他人的博客,主要用來(lái)記錄資料復(fù)習(xí)萤衰。

? ? ? ? 1艰争、java坏瞄,android內(nèi)存分配與回收機(jī)制;

? ? ? ? 2甩卓、android內(nèi)存泄露常見(jiàn)原因與OOM鸠匀;

? ? ? ? 3、內(nèi)存分析工具M(jìn)AT 和 studio?Monitor

一逾柿、java , android內(nèi)存分配與回收機(jī)制:

? ? 1缀棍、靜態(tài)存儲(chǔ)、棧區(qū)机错、堆區(qū)

? ??????Java/Android 程序運(yùn)行時(shí)的內(nèi)存分配有三種策略爬范,分別是靜態(tài)的,棧式的和堆式的弱匪,對(duì)應(yīng)的三種存儲(chǔ)策略使用的內(nèi)存空間主要分別是靜態(tài)存儲(chǔ)區(qū)(方法區(qū))青瀑、堆區(qū)和棧區(qū):

靜態(tài)存儲(chǔ)區(qū)(方法區(qū))

內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好,這塊內(nèi)存在程序整個(gè)運(yùn)行期間都存在,它主要是用來(lái)存放靜態(tài)數(shù)據(jù)斥难、全局 static 數(shù)據(jù)和常量枝嘶;

棧區(qū)

在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)部局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建哑诊,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放群扶,棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高镀裤,但是分配的內(nèi)存容量有限竞阐;

堆區(qū)

亦稱為動(dòng)態(tài)內(nèi)存分配,Java/Android 程序在適當(dāng)?shù)臅r(shí)候使用 new 關(guān)鍵字申請(qǐng)所需要大小的對(duì)象內(nèi)存淹禾,然后通過(guò) GC 決定在不需要這塊對(duì)象內(nèi)存的時(shí)候回收它,但是由于我們的疏忽導(dǎo)致該對(duì)象在不需要繼續(xù)使用的之后茴扁,GC 仍然沒(méi)辦法回收該內(nèi)存區(qū)域铃岔,這就代表發(fā)生了內(nèi)存泄漏。

2峭火、堆區(qū)和棧區(qū)的區(qū)別:?

  在函數(shù)中定義的一些基本類(lèi)型的變量和對(duì)象的引用變量(也就是局部變量的引用)都是在函數(shù)的棧內(nèi)存分配的毁习,當(dāng)在一段代碼塊中定義一個(gè)變量時(shí),Java 就在棧中為這個(gè)變量分配內(nèi)存空間卖丸,當(dāng)超過(guò)變量的作用域后纺且,Java 會(huì)自動(dòng)釋放掉為該變量分配的內(nèi)存空間,該內(nèi)存空間可以立刻被重新使用稍浆;堆內(nèi)存用于存放所有由 new 創(chuàng)建的對(duì)象(內(nèi)容包括該對(duì)象其中的所有成員變量)和數(shù)組载碌,在堆中分配的內(nèi)存是由 GC 來(lái)管理的,在堆中產(chǎn)生了一個(gè)對(duì)象或者數(shù)組后衅枫,還可以在棧中生成一個(gè)引用指向這個(gè)堆中對(duì)象的內(nèi)存區(qū)域嫁艇,以后就可以通過(guò)棧中這個(gè)引用變量來(lái)訪問(wèn)堆中的這個(gè)引用指向的對(duì)象或者數(shù)組。

3弦撩、?Dalvik到ART的進(jìn)化

????????Android在4.4之前一直使用的Dalvik虛擬機(jī)作為App的運(yùn)行VM的, 4.4中引入了ART作為開(kāi)發(fā)者備選, 5.0起正式將ART作為默認(rèn)VM了步咪。其中?Dalvik采用的是JIT技術(shù),在應(yīng)用程序啟動(dòng)時(shí)益楼,JIT通過(guò)進(jìn)行連續(xù)的性能分析來(lái)優(yōu)化程序代碼的執(zhí)行,猾漫,在程序運(yùn)行的過(guò)程中,,Dalvik在不斷的進(jìn)行將字節(jié)碼編譯成機(jī)器碼的工作感凤。而ART 取自 Android RunTime. Android用其取代Dalvik悯周,主要目的就是為了提升運(yùn)行性能。所以陪竿,ART相比Dalvik有幾個(gè)關(guān)鍵的提升:

引入AOT(ahead-of-time)預(yù)編譯技術(shù)

在安裝apk的過(guò)程中, ART會(huì)使用dex2oat程序所有的字節(jié)碼預(yù)編譯成了機(jī)器碼. 應(yīng)用程序運(yùn)行過(guò)程中無(wú)需進(jìn)行實(shí)時(shí)的編譯工作, 只需要進(jìn)行直接調(diào)用. 故而提高了應(yīng)用程序的運(yùn)行效率.

提高GC效率

由原來(lái)的兩次GC暫停減少為一次.

以較少的GC時(shí)間回收最近分配的, 短命的對(duì)象.

提升GC工程學(xué), 使并發(fā)GC更及時(shí).

壓縮GC, 以減少后臺(tái)內(nèi)存使用和內(nèi)存碎片.

4队橙、Dalvik分配內(nèi)存的過(guò)程

????????Dalvik 虛擬機(jī)實(shí)現(xiàn)了一個(gè) dvmAllocObject 函數(shù),每當(dāng) Dalvik 虛擬機(jī)需要為對(duì)象分配內(nèi)存時(shí),就會(huì)調(diào)用函數(shù) dvmAllocObject捐康,例如仇矾,當(dāng) Dalvik 虛擬機(jī)的解釋器遇到一個(gè) new 指令時(shí),它就會(huì)調(diào)用函數(shù) dvmAllocObject解总;

????????函數(shù) dvmAllocObject 調(diào)用函數(shù) dvmMalloc 從 Java 堆中分配一塊指定大小的內(nèi)存給新創(chuàng)建的對(duì)象使用贮匕,如果分配成功,那么接下來(lái)就先使用宏 DVM_OBJECT_INIT 來(lái)初始化新創(chuàng)建對(duì)象的成員變量 clazz花枫,使得新創(chuàng)建的對(duì)象可以與某個(gè)特定的類(lèi)關(guān)聯(lián)起來(lái)刻盐,接著再調(diào)用函數(shù) dvmTrackAllocation 記錄當(dāng)前的內(nèi)存分配信息,以便通知 DDMS劳翰。函數(shù) dvmMalloc 返回的只是一塊內(nèi)存地址敦锌,這是沒(méi)有類(lèi)型的,但是由于每一個(gè) Java 對(duì)象都是從 Object 類(lèi)繼承下來(lái)的佳簸,因此函數(shù) dvmAllocObject 可以將獲得的沒(méi)有類(lèi)型的內(nèi)存塊強(qiáng)制轉(zhuǎn)換為一個(gè) Object 對(duì)象乙墙;

????????dvmMalloc 函數(shù)接著調(diào)用到了另一個(gè)函數(shù) tryMalloc ,真正執(zhí)行內(nèi)存分配操作的就是這個(gè) tryMalloc 函數(shù)生均,dvmMalloc 函數(shù)操作如果分配內(nèi)存成功听想,則記錄當(dāng)前線程成功分配的內(nèi)存字節(jié)數(shù)和對(duì)象數(shù)等信息;否則的話马胧,就記錄當(dāng)前線程失敗分配的內(nèi)存字節(jié)數(shù)和對(duì)象等信息汉买,方便通過(guò) DDMS 等工具對(duì)內(nèi)存使用信息進(jìn)行統(tǒng)計(jì),同時(shí)會(huì)調(diào)用函數(shù) throwOOME 拋出一個(gè) OOM 異常佩脊;

5蛙粘、Dalvik進(jìn)行GC的過(guò)程

Google IO 2011 大會(huì)的圖就很好的展示了Android 4.4 版本之下的回收策略

????????圖中的每個(gè)圓節(jié)點(diǎn)代表對(duì)象的內(nèi)存資源,箭頭代表可達(dá)路徑威彰,當(dāng)一個(gè)圓節(jié)點(diǎn)和 GC Roots 存在可達(dá)的路徑時(shí)组题,表示當(dāng)前它指向的內(nèi)存資源正在被引用,虛擬機(jī)是無(wú)法對(duì)其進(jìn)行回收的(圖中的黃色節(jié)點(diǎn))抱冷;反過(guò)來(lái)崔列,如果當(dāng)前的圓節(jié)點(diǎn)和 GC Roots 不存在可達(dá)路徑,則意味著這塊對(duì)象的內(nèi)存資源不再被程序引用旺遮,系統(tǒng)虛擬機(jī)可以在 GC 的時(shí)候?qū)⑵鋬?nèi)存回收掉赵讯。具體點(diǎn)來(lái)說(shuō),Java/Android 的內(nèi)存垃圾回收機(jī)制是從程序的主要運(yùn)行對(duì)象(如靜態(tài)對(duì)象/寄存器/棧上指向的內(nèi)存對(duì)象等耿眉,對(duì)應(yīng)上面的 GC Roots)開(kāi)始檢查調(diào)用鏈边翼,當(dāng)遍歷一遍后得到上述這些無(wú)法回收的對(duì)象和他們所引用的對(duì)象鏈組成無(wú)法回收的對(duì)象集合,而剩余其他的孤立對(duì)象(集)就作為垃圾被 GC 回收鸣剪。GC 為了能夠正確釋放對(duì)象组底,必須監(jiān)控每一個(gè)對(duì)象的運(yùn)行狀態(tài)丈积,包括對(duì)象的申請(qǐng)、引用债鸡、被引用江滨、賦值等。監(jiān)視對(duì)象狀態(tài)是為了更加準(zhǔn)確地厌均、及時(shí)地釋放對(duì)象唬滑,而釋放對(duì)象的根本原則就是該對(duì)象不再被引用。

6棺弊、ART 的GC過(guò)程

????????ART 為新創(chuàng)建對(duì)象分配內(nèi)存的過(guò)程和 Dalvik VM 幾乎是一樣的晶密,區(qū)別僅僅在于垃圾收集的方式和策略不一樣。 ART 運(yùn)行時(shí)為從 DEX 字節(jié)碼翻譯得到的 Native 代碼提供的一個(gè)函數(shù)調(diào)用表中模她,有一個(gè) pAllocObject 接口是用來(lái)分配對(duì)象的稻艰,當(dāng) ART 運(yùn)行時(shí)以 Quick 模式運(yùn)行在 ARM 體系結(jié)構(gòu)時(shí),上述提到的 pAllocObject 接口由函數(shù) art_quick_alloc_object 來(lái)實(shí)現(xiàn)侈净,art_quick_alloc_object 是一段匯編代碼尊勿,最終經(jīng)過(guò)一系列的調(diào)用之后最終會(huì)調(diào)用 ART 運(yùn)行時(shí)內(nèi)部的 Heap 對(duì)象的成員函數(shù) AllocObject 在堆上分配對(duì)象(具體的過(guò)程:ART運(yùn)行時(shí)為新創(chuàng)建對(duì)象分配內(nèi)存的過(guò)程分析),其中要分配的大小保存在當(dāng)前 Class 對(duì)象的成員變量 object_size_ 中用狱。(具體參考博客:http://blog.csdn.net/self_study/article/details/61919483)

7运怖、ART相對(duì)Dalivk的優(yōu)勢(shì)

????????在 Android 4.4 版本以及之后就使用了 ART 運(yùn)行時(shí)拼弃,在安裝的時(shí)候就將應(yīng)用翻譯成機(jī)器碼執(zhí)行夏伊,效率比起以前的 Dalvik 虛擬機(jī)更高,但是缺點(diǎn)就是安裝之后的應(yīng)用體積變大和安裝的時(shí)間會(huì)變長(zhǎng)吻氧,不過(guò)相對(duì)于優(yōu)點(diǎn)來(lái)說(shuō)溺忧,這點(diǎn)缺點(diǎn)不算什么。ART 運(yùn)行時(shí)與 Dalvik 虛擬機(jī)一樣盯孙,都使用了 Mark-Sweep 算法進(jìn)行垃圾回收鲁森,因此它們的垃圾回收流程在總體上是一致的,但是 ART 運(yùn)行時(shí)對(duì)堆的劃分更加細(xì)致振惰,因而在此基礎(chǔ)上實(shí)現(xiàn)了更多樣的回收策略歌溉。不同的策略有不同的回收力度,力度越大的回收策略每次回收的內(nèi)存就越多骑晶,并且它們都有各自的使用情景痛垛,這樣就可以使得每次執(zhí)行 GC 時(shí),可以最大限度地減少應(yīng)用程序停頓桶蛔。

二匙头、內(nèi)存泄露以及OOM原因及解決辦法:

? ?1、 內(nèi)存泄露

????????內(nèi)存對(duì)象的泄漏仔雷,會(huì)導(dǎo)致一些不再使用的對(duì)象無(wú)法及時(shí)釋放蹂析,這樣一方面占用了寶貴的內(nèi)存空間舔示,很容易導(dǎo)致后續(xù)需要分配內(nèi)存的時(shí)候,空閑空間不足而出現(xiàn)OOM电抚。顯然惕稻,這還使得每級(jí)Generation的內(nèi)存區(qū)域可用空間變小,GC就會(huì)更容易被觸發(fā)喻频,容易出現(xiàn)內(nèi)存抖動(dòng)缩宜,從而引起性能問(wèn)題(如圖15所示)。

圖15

最新的LeakCanary開(kāi)源控件甥温,可以很好的幫助我們發(fā)現(xiàn)內(nèi)存泄露的情況锻煌,更多關(guān)于LeakCanary的介紹,請(qǐng)看這里中文使用說(shuō)明)姻蚓。另外也可以使用傳統(tǒng)的MAT工具查找內(nèi)存泄露宋梧,請(qǐng)參考這里便捷的中文資料)。

1)注意Activity的泄漏

通常來(lái)說(shuō)狰挡,Activity的泄漏是內(nèi)存泄漏里面最嚴(yán)重的問(wèn)題捂龄,它占用的內(nèi)存多,影響面廣加叁,我們需要特別注意以下兩種情況導(dǎo)致的Activity泄漏:

內(nèi)部類(lèi)引用導(dǎo)致Activity的泄漏

最典型的場(chǎng)景是Handler導(dǎo)致的Activity泄漏倦沧,如果Handler中有延遲的任務(wù)或者是等待執(zhí)行的任務(wù)隊(duì)列過(guò)長(zhǎng),都有可能因?yàn)镠andler繼續(xù)執(zhí)行而導(dǎo)致Activity發(fā)生泄漏它匕。此時(shí)的引用關(guān)系鏈?zhǔn)荓ooper -> MessageQueue -> Message -> Handler -> Activity展融。為了解決這個(gè)問(wèn)題,可以在UI退出之前豫柬,執(zhí)行remove Handler消息隊(duì)列中的消息與runnable對(duì)象告希。或者是使用Static + WeakReference的方式來(lái)達(dá)到斷開(kāi)Handler與Activity之間存在引用關(guān)系的目的烧给。

Activity Context被傳遞到其他實(shí)例中燕偶,這可能導(dǎo)致自身被引用而發(fā)生泄漏。

內(nèi)部類(lèi)引起的泄漏不僅僅會(huì)發(fā)生在Activity上础嫡,其他任何內(nèi)部類(lèi)出現(xiàn)的地方指么,都需要特別留意!我們可以考慮盡量使用static類(lèi)型的內(nèi)部類(lèi)榴鼎,同時(shí)使用WeakReference的機(jī)制來(lái)避免因?yàn)榛ハ嘁枚霈F(xiàn)的泄露伯诬。

2)考慮使用Application Context而不是Activity Context

對(duì)于大部分非必須使用Activity Context的情況(Dialog的Context就必須是Activity Context),我們都可以考慮使用Application Context而不是Activity的Context檬贰,這樣可以避免不經(jīng)意的Activity泄露姑廉。

3)注意臨時(shí)Bitmap對(duì)象的及時(shí)回收

雖然在大多數(shù)情況下,我們會(huì)對(duì)Bitmap增加緩存機(jī)制翁涤,但是在某些時(shí)候桥言,部分Bitmap是需要及時(shí)回收的萌踱。例如臨時(shí)創(chuàng)建的某個(gè)相對(duì)比較大的bitmap對(duì)象,在經(jīng)過(guò)變換得到新的bitmap對(duì)象之后号阿,應(yīng)該盡快回收原始的bitmap并鸵,這樣能夠更快釋放原始bitmap所占用的空間。

需要特別留意的是Bitmap類(lèi)里面提供的createBitmap()方法扔涧,如圖16所示:

圖16 ?createBitmap()方法

這個(gè)函數(shù)返回的bitmap有可能和source bitmap是同一個(gè)园担,在回收的時(shí)候,需要特別檢查source bitmap與return bitmap的引用是否相同枯夜,只有在不等的情況下弯汰,才能夠執(zhí)行source bitmap的recycle方法。

4)注意監(jiān)聽(tīng)器的注銷(xiāo)

在Android程序里面存在很多需要register與unregister的監(jiān)聽(tīng)器湖雹,我們需要確保在合適的時(shí)候及時(shí)unregister那些監(jiān)聽(tīng)器咏闪。自己手動(dòng)add的listener,需要記得及時(shí)remove這個(gè)listener摔吏。

5)注意緩存容器中的對(duì)象泄漏

有時(shí)候鸽嫂,我們?yōu)榱颂岣邔?duì)象的復(fù)用性把某些對(duì)象放到緩存容器中,可是如果這些對(duì)象沒(méi)有及時(shí)從容器中清除征讲,也是有可能導(dǎo)致內(nèi)存泄漏的据某。例如,針對(duì)2.3的系統(tǒng)诗箍,如果把drawable添加到緩存容器癣籽,因?yàn)閐rawable與View的強(qiáng)應(yīng)用,很容易導(dǎo)致activity發(fā)生泄漏扳还。而從4.0開(kāi)始才避,就不存在這個(gè)問(wèn)題橱夭。解決這個(gè)問(wèn)題氨距,需要對(duì)2.3系統(tǒng)上的緩存drawable做特殊封裝,處理引用解綁的問(wèn)題棘劣,避免泄漏的情況俏让。

6)注意WebView的泄漏

Android中的WebView存在很大的兼容性問(wèn)題,不僅僅是Android系統(tǒng)版本的不同對(duì)WebView產(chǎn)生很大的差異茬暇,另外不同的廠商出貨的ROM里面WebView也存在著很大的差異首昔。更嚴(yán)重的是標(biāo)準(zhǔn)的WebView存在內(nèi)存泄露的問(wèn)題,請(qǐng)看這里糙俗。所以通常根治這個(gè)問(wèn)題的辦法是為WebView開(kāi)啟另外一個(gè)進(jìn)程勒奇,通過(guò)AIDL與主進(jìn)程進(jìn)行通信,WebView所在的進(jìn)程可以根據(jù)業(yè)務(wù)的需要選擇合適的時(shí)機(jī)進(jìn)行銷(xiāo)毀巧骚,從而達(dá)到內(nèi)存的完整釋放赊颠。

7)注意Cursor對(duì)象是否及時(shí)關(guān)閉

在程序中我們經(jīng)常會(huì)進(jìn)行查詢數(shù)據(jù)庫(kù)的操作格二,但時(shí)常會(huì)存在不小心使用Cursor之后沒(méi)有及時(shí)關(guān)閉的情況。這些Cursor的泄露竣蹦,反復(fù)多次出現(xiàn)的話會(huì)對(duì)內(nèi)存管理產(chǎn)生很大的負(fù)面影響顶猜,我們需要謹(jǐn)記對(duì)Cursor對(duì)象的及時(shí)關(guān)閉。


2痘括、避免OOM

減小對(duì)象的內(nèi)存占用

避免OOM的第一步就是要盡量減少新分配出來(lái)的對(duì)象占用內(nèi)存的大小长窄,盡量使用更加輕量的對(duì)象。

1)使用更加輕量的數(shù)據(jù)結(jié)構(gòu)

例如纲菌,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)挠日。圖8演示了HashMap的簡(jiǎn)要工作原理,相比起Android專(zhuān)門(mén)為移動(dòng)操作系統(tǒng)編寫(xiě)的ArrayMap容器翰舌,在大多數(shù)情況下肆资,都顯示效率低下,更占內(nèi)存灶芝。通常的HashMap的實(shí)現(xiàn)方式更加消耗內(nèi)存郑原,因?yàn)樗枰粋€(gè)額外的實(shí)例對(duì)象來(lái)記錄Mapping操作。另外夜涕,SparseArray更加高效犯犁,在于他們避免了對(duì)key與value的自動(dòng)裝箱(autoboxing),并且避免了裝箱后的解箱女器。

關(guān)于更多ArrayMap/SparseArray的討論酸役,請(qǐng)參考《Android性能優(yōu)化典范(三)》的前三個(gè)段落。

2)避免在Android里面使用Enum

Android官方培訓(xùn)課程提到過(guò)“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”驾胆,具體原理請(qǐng)參考《Android性能優(yōu)化典范(三)》涣澡,所以請(qǐng)避免在Android里面使用到枚舉。

3)減小Bitmap對(duì)象的內(nèi)存占用

Bitmap是一個(gè)極容易消耗內(nèi)存的大胖子丧诺,減小創(chuàng)建出來(lái)的Bitmap的內(nèi)存占用可謂是重中之重入桂,通常來(lái)說(shuō)有以下2個(gè)措施:

inSampleSize:縮放比例,在把圖片載入內(nèi)存之前驳阎,我們需要先計(jì)算出一個(gè)合適的縮放比例抗愁,避免不必要的大圖載入。

decode format:解碼格式呵晚,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8蜘腌,存在很大差異。

4)使用更小的圖片

在涉及給到資源圖片時(shí)饵隙,我們需要特別留意這張圖片是否存在可以壓縮的空間撮珠,是否可以使用更小的圖片。盡量使用更小的圖片不僅可以減少內(nèi)存的使用金矛,還能避免出現(xiàn)大量的InflationException芯急。假設(shè)有一張很大的圖片被XML文件直接引用倘潜,很有可能在初始化視圖時(shí)會(huì)因?yàn)閮?nèi)存不足而發(fā)生InflationException,這個(gè)問(wèn)題的根本原因其實(shí)是發(fā)生了OOM志于。

內(nèi)存對(duì)象的重復(fù)利用

大多數(shù)對(duì)象的復(fù)用涮因,最終實(shí)施的方案都是利用對(duì)象池技術(shù),要么是在編寫(xiě)代碼時(shí)顯式地在程序里創(chuàng)建對(duì)象池伺绽,然后處理好復(fù)用的實(shí)現(xiàn)邏輯养泡。要么就是利用系統(tǒng)框架既有的某些復(fù)用特性,減少對(duì)象的重復(fù)創(chuàng)建奈应,從而降低內(nèi)存的分配與回收(如圖9所示)澜掩。

圖9 ?對(duì)象池技術(shù)

在Android上面最常用的一個(gè)緩存算法是LRU(Least Recently Use),簡(jiǎn)要操作原理如圖10所示杖挣。

圖10 ?LRU簡(jiǎn)要操作原理

1)復(fù)用系統(tǒng)自帶的資源

Android系統(tǒng)本身內(nèi)置了很多的資源肩榕,比如字符串、顏色惩妇、圖片株汉、動(dòng)畫(huà)、樣式以及簡(jiǎn)單布局等歌殃,這些資源都可以在應(yīng)用程序中直接引用乔妈。這樣做不僅能減少應(yīng)用程序的自身負(fù)重,減小APK的大小氓皱,還可以在一定程度上減少內(nèi)存的開(kāi)銷(xiāo)路召,復(fù)用性更好。但是也有必要留意Android系統(tǒng)的版本差異性波材,對(duì)那些不同系統(tǒng)版本上表現(xiàn)存在很大差異股淡、不符合需求的情況,還是需要應(yīng)用程序自身內(nèi)置進(jìn)去廷区。

2)注意在ListView/GridView等出現(xiàn)大量重復(fù)子組件的視圖里對(duì)ConvertView的復(fù)用唯灵,如圖11所示。

圖11

3)Bitmap對(duì)象的復(fù)用

在ListView與GridView等顯示大量圖片的控件里躲因,需要使用LRU的機(jī)制來(lái)緩存處理好的Bitmap早敬,如圖12所示忌傻。

圖12

利用inBitmap的高級(jí)特性提高Android系統(tǒng)在Bitmap分配與釋放執(zhí)行效率(注:3.0以及4.4以后存在一些使用限制上的差異)。使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經(jīng)存在的內(nèi)存區(qū)域水孩,新解碼的Bitmap會(huì)嘗試去使用之前那張Bitmap在Heap中所占據(jù)的pixel data內(nèi)存區(qū)域镰矿,而不是去問(wèn)內(nèi)存重新申請(qǐng)一塊區(qū)域來(lái)存放Bitmap。利用這種特性俘种,即使是上千張的圖片秤标,也只會(huì)僅僅只需要占用屏幕所能夠顯示的圖片數(shù)量的內(nèi)存大小绝淡,如圖13所示。

圖13 ?利用inBitmap的高級(jí)特性提高Android在Bitmap分配與釋放執(zhí)行效率

使用inBitmap需要注意幾個(gè)限制條件:

在SDK 11 -> 18之間苍姜,重用的Bitmap大小必須是一致的牢酵。例如給inBitmap賦值的圖片大小為100-100,那么新申請(qǐng)的Bitmap必須也為100-100才能夠被重用衙猪。從SDK 19開(kāi)始馍乙,新申請(qǐng)的Bitmap大小必須小于或者等于已經(jīng)賦值過(guò)的Bitmap大小。

新申請(qǐng)的Bitmap與舊的Bitmap必須有相同的解碼格式垫释。例如大家都是8888的丝格,如果前面的Bitmap是8888,那么就不能支持4444與565格式的Bitmap了棵譬。我們可以創(chuàng)建一個(gè)包含多種典型可重用Bitmap的對(duì)象池显蝌,這樣后續(xù)的Bitmap創(chuàng)建都能夠找到合適的“模板”去進(jìn)行重用,如圖14所示订咸。

圖14

另外曼尊,在2.x的系統(tǒng)上,盡管Bitmap是分配在Native層脏嚷,但還是無(wú)法避免被計(jì)算到OOM的引用計(jì)數(shù)器里涩禀。這里提示一下,不少應(yīng)用會(huì)通過(guò)反射vBitmapFactory.Options里面的inNativeAlloc來(lái)達(dá)到擴(kuò)大使用內(nèi)存的目的然眼,但是如果大家都這么做艾船,對(duì)系統(tǒng)整體會(huì)造成一定的負(fù)面影響,建議謹(jǐn)慎采納高每。

4)避免在onDraw方法里面執(zhí)行對(duì)象的創(chuàng)建

類(lèi)似onDraw等頻繁調(diào)用的方法屿岂,一定需要注意避免在這里做創(chuàng)建對(duì)象的操作,因?yàn)樗麜?huì)迅速增加內(nèi)存的使用鲸匿,而且很容易引起頻繁的gc爷怀,甚至是內(nèi)存抖動(dòng)。

5)StringBuilder

在有些時(shí)候带欢,代碼中會(huì)需要使用到大量的字符串拼接的操作运授,這種時(shí)候有必要考慮使用StringBuilder來(lái)替代頻繁的“+”。

三乔煞、內(nèi)存分析工具M(jìn)AT 和 studio?Monitor

(參考博客:http://www.reibang.com/p/080473ae050b)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吁朦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子渡贾,更是在濱河造成了極大的恐慌逗宜,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異纺讲,居然都是意外死亡擂仍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)熬甚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)逢渔,“玉大人,你說(shuō)我怎么就攤上這事乡括「淳郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵粟判,是天一觀的道長(zhǎng)婉陷。 經(jīng)常有香客問(wèn)我我碟,道長(zhǎng)赎败,這世上最難降的妖魔是什么赚抡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮呻澜,結(jié)果婚禮上递礼,老公的妹妹穿的比我還像新娘。我一直安慰自己羹幸,他們只是感情好脊髓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著栅受,像睡著了一般将硝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屏镊,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天依疼,我揣著相機(jī)與錄音,去河邊找鬼而芥。 笑死律罢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的棍丐。 我是一名探鬼主播误辑,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼歌逢!你這毒婦竟也來(lái)了巾钉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤趋翻,失蹤者是張志新(化名)和其女友劉穎睛琳,沒(méi)想到半個(gè)月后盒蟆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體踏烙,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡师骗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了讨惩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辟癌。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖荐捻,靈堂內(nèi)的尸體忽然破棺而出黍少,到底是詐尸還是另有隱情,我是刑警寧澤处面,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布厂置,位于F島的核電站,受9級(jí)特大地震影響魂角,放射性物質(zhì)發(fā)生泄漏昵济。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一野揪、第九天 我趴在偏房一處隱蔽的房頂上張望访忿。 院中可真熱鬧,春花似錦斯稳、人聲如沸海铆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)卧斟。三九已至,卻和暖如春憎茂,著一層夾襖步出監(jiān)牢的瞬間唆涝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工唇辨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留廊酣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓赏枚,卻偏偏與公主長(zhǎng)得像亡驰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饿幅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容