1 回答

TA貢獻(xiàn)1841條經(jīng)驗(yàn) 獲得超3個(gè)贊
已經(jīng)大半年不碰Android了,以下是一些記憶中的經(jīng)驗(yàn),供參考。
首先確實(shí)是內(nèi)存問題,這些都是DalvikVM的GC日志,格式如下:
[GC原因] [釋放了多少VM內(nèi)存], [VM堆內(nèi)存統(tǒng)計(jì)], [外部?jī)?nèi)存統(tǒng)計(jì)], [VM暫停時(shí)間]
其中[原因]的內(nèi)容可以參考Android源碼中/dalvik/vm/alloc/Heap.h中enum GcReason的定義:
typedef enum { /* Not enough space for an "ordinary" Object to be allocated. */ GC_FOR_MALLOC, /* Automatic GC triggered by exceeding a heap occupancy threshold. */ GC_CONCURRENT, /* Explicit GC via Runtime.gc(), VMRuntime.gc(), or SIGUSR1. */ GC_EXPLICIT, /* GC to try to reduce heap footprint to allow more non-GC'ed memory. */ GC_EXTERNAL_ALLOC, /* GC to dump heap contents to a file, only used under WITH_HPROF */ GC_HPROF_DUMP_HEAP} GcReason;
你日志中的GC_EXPLICIT就是說有調(diào)用過Runtime.gc()或VMRuntime.gc()(可能是SDK調(diào)的)。然后[VM暫停時(shí)間]是“hold the whole world”,就是所有東西都停止,會(huì)非常影響體驗(yàn),就是造成你覺得操作卡頓的主要原因。
然后是解決方案。在ListView/GridView之類的東西里面展現(xiàn)圖片很容易就會(huì)遇上內(nèi)存問題,說白了就是內(nèi)存里的圖片太大內(nèi)存不足,好點(diǎn)的引發(fā)GC卡頓,差點(diǎn)的就直接OOM了。所以有幾個(gè)解決思路:
1. 減少圖片文件大小
調(diào)整圖片大小或是降低圖片色彩值或是修改圖片格式都可以有效降低圖片文件大小。例如色彩較豐富的圖片jpg就比png要小一些,能做點(diǎn)九的盡量點(diǎn)九,減少色彩值數(shù)量可以顯著降低png圖片大小,特別是如果可以控制在256種顏色之內(nèi)就可以啟動(dòng)png的色彩索引方案,加大jpg的壓縮比例也可以讓圖片小很多。此方案的缺點(diǎn)則是圖片必須是由我們自己處理的,例如靜態(tài)資源或是從自己服務(wù)器獲取的圖,可以做預(yù)先處理。
2. 減少圖片在內(nèi)存中的大小
圖片文件有多大并不代表它在內(nèi)存里就占用多少空間,因?yàn)槲覀兛梢栽趫D片加載過程中對(duì)其數(shù)據(jù)進(jìn)行一些修改以達(dá)到減少在內(nèi)存中占用的效果。一般來說有兩種辦法:
1) 動(dòng)態(tài)修改圖片色值,例如從8888改為565這種,以前我們用過對(duì)大圖片非常有效。
2) 先用僅讀取圖片的bounds,然后依此縮小圖片(代碼網(wǎng)上很多),銷毀掉大圖僅使用小圖,再做顯示處理,也是一個(gè)常用方法。
3. 更好的利用內(nèi)存
首先要理解Android中bitmap用的是native的內(nèi)存,你可以理解為是C用的那段內(nèi)存,與java用的不在一起。Android從3.2版本以后加強(qiáng)了這塊的管理,使得native內(nèi)存會(huì)隨著JVM的GC一起回收,所以會(huì)大大減少這塊的問題(3.2之前的版本也會(huì)回收,但因?yàn)榕cJava GC不同步所以一般回收不及時(shí)就會(huì)暴內(nèi)存溢出,因此需要開發(fā)者手工調(diào)用recycle())
然后遵循一條法則:“永遠(yuǎn)只存放要顯示的圖片在內(nèi)存中”,也就是說只有用戶看得見的圖片才在內(nèi)存里,看不見的就銷毀(recycle()),需要時(shí)再重新加載。這點(diǎn)與ListView的滑動(dòng)窗口是一個(gè)道理。
要做到這些,recycle()總是需要自己寫邏輯(對(duì)于3.2之前的版本),但留在JVM內(nèi)存的那部分可以交給系統(tǒng)來管理,以前較為常用的建議是SoftReference和WeakReference,現(xiàn)在一般建議使用Android自帶的緩存類LruCache或LruDiskCache,它會(huì)自動(dòng)按照LRU算法銷毀隊(duì)列尾部的元素(最不常用),而非看GC心情。
另外樓主也應(yīng)該盡量減少View的個(gè)數(shù),能合并的盡量合并,盡量少使用重量級(jí)的View(可以查看View的源碼由其成員變量組成來確定是輕是重)。如果以上這些都做了依然有大量的GC,建議在業(yè)務(wù)可接受的范圍內(nèi)與產(chǎn)品討論簡(jiǎn)化界面。
- 1 回答
- 0 關(guān)注
- 223 瀏覽
添加回答
舉報(bào)