都知道在Android中, 每個(gè)應(yīng)用所使用的內(nèi)存是有限的,現(xiàn)在的手機(jī)通常最大的內(nèi)存使用為256M, 目前還沒發(fā)現(xiàn)Android中一個(gè)應(yīng)用的最大內(nèi)存分配超過256M的(經(jīng)測(cè)試華為手機(jī)的最大內(nèi)存是385M)
相關(guān)API:
ActivityManager.getMemoryClass(),首先獲取系統(tǒng)服務(wù)中的ActivityManager
如下:
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
可以獲取到相關(guān)信息
最近一直被項(xiàng)目的OOM問題困擾, 在網(wǎng)上查閱相關(guān)資料,前前后后讀了不下于30篇,這些篇幅講解的東西都是千篇一律,并沒有解決到實(shí)際問題
也在慕課網(wǎng)學(xué)習(xí)了內(nèi)存優(yōu)化章節(jié)
這是慕課網(wǎng)講師的PPT,我截屏的
這里來仔細(xì)分析一下:
第一個(gè), ?注意臨時(shí)Bitmap對(duì)象的及時(shí)回收, 來看下相關(guān)API
直接上圖
經(jīng)過我無數(shù)次的使用Android studio工具自帶的MAT分析工具后, 得出一個(gè)很嚴(yán)謹(jǐn)?shù)慕Y(jié)論, 此方法并不奏效...
Android中Bitmap的內(nèi)存存放在堆區(qū), Google 的Bitmap的recycle方法注釋也可以了解到
Android歷史版本不是很清楚, 據(jù)說Android3.0之前Bitmap是存放在native區(qū)域,可以進(jìn)行手動(dòng)釋放,然而3.0之后Bitmap是存放在Java層的堆區(qū),沒錯(cuò)是heap, 內(nèi)存管理直接交由系統(tǒng)GC管理,你還這樣釋放資源有意義?無非是給自己的一點(diǎn)心理安慰罷了, 告訴你沒卵用
又有人在說要釋放內(nèi)存使用System.gc() ??? ?對(duì)就是主動(dòng)觸發(fā)垃圾回收,這個(gè)API是開發(fā)者自行調(diào)用的嗎?那么系統(tǒng)管理內(nèi)存還有什么意義?這不是誤人子弟嗎,這個(gè)API不能調(diào)用的, 因?yàn)闆]卵用的, 具體自己參照MAT工具自行分析.即便垃圾回收真的被觸發(fā)了, 所有線程停滯由系統(tǒng)來清理垃圾, 造成的后果是嚴(yán)重卡頓!!!
再看一個(gè)API:
我在網(wǎng)上苦苦追尋內(nèi)存過高的問題后,發(fā)現(xiàn)了這個(gè)API,經(jīng)過無數(shù)次實(shí)踐后我得出一個(gè)結(jié)論,沒卵用...開發(fā)者可以拋棄它
綜上所訴, 第一點(diǎn)講解的內(nèi)存優(yōu)化問題可以直接PASS掉, 無非給自己一點(diǎn)心理安慰: 我已經(jīng)處理好了內(nèi)存問題, 程序不會(huì)OOM?
第二點(diǎn). 避免Bitmap的浪費(fèi)
直接說結(jié)論, 這個(gè)是非常行之有效的,并且是一定能解決問題的
具體怎么操作呢? 自己實(shí)現(xiàn)LruCache這個(gè)類, 就是這么弄, 原理就是解碼復(fù)用, 在內(nèi)存中已經(jīng)解碼好的Bitmap直接拿出來使用, 沒有的在加載到內(nèi)存進(jìn)行解析, 這個(gè)非常有效,但是并不能讓你避免OOM
第三點(diǎn), try-catch某些大內(nèi)存分配的操作
這點(diǎn)上,我又要開始疑問了, 我Java功底不是很好
Java中發(fā)生內(nèi)存溢出時(shí),拋出的是OutOfMemoryError, 它的父類是VirtualMachineError
這玩意能catch住? 它屬于Error范疇, 你能捕獲?請(qǐng)Java大神出來說一下,我解釋不清楚
第四點(diǎn), 加載Bitmap 縮放比例, 解碼格式, 局部加載
先來分析一下縮放比例:
按照市面上主流的手機(jī)分辨率來分析現(xiàn)在Android主流的分辨率是1920X1080, 如果一個(gè)ImageView控件剛好就是屏幕全屏,怎么說?直接占用掉8M內(nèi)存, 想想一個(gè)實(shí)際的需求情況
一個(gè)查看大圖的頁面, 不斷的關(guān)閉,打開查看新的大圖,問題就來了,內(nèi)存一直在暴增,遲早會(huì)突破界限OOM掉
分辨率是2K屏呢? 更恐怖了, 隨著手機(jī)設(shè)備的屏幕分辨率提升, 加載圖像需要的內(nèi)存也是倍增的, 因?yàn)閼?yīng)用的最大內(nèi)存并沒有增加
結(jié)論: 縮放比例可以有效的降低內(nèi)存占用問題, 但不是絕對(duì)的救命稻草, 該縮放的還是要縮放,而且必須縮放,就是采樣 ?現(xiàn)在通常都是圖片加載框架來完成,類似Glide.Picasso,Fresco等,他們可以幫助你減少工作量, 內(nèi)存問題還是存在
再來分析一下解碼格式:
這個(gè)跟縮放比例效果差不多, 只是同樣的分辨率的圖片加載到內(nèi)存中時(shí)占用內(nèi)存減少了
比如ARGB_8888 共32位
RGB_565 ?共16位
ARGB_4444 共16位
很明顯這樣格式圖片加載的內(nèi)存情況是ARGB_8888是其他格式的兩倍內(nèi)存
另外的問題是ARGB_8888看起來很清晰的, 其它的看起來圖片有種糊了的感覺,自己選擇吧
結(jié)論, 降低內(nèi)存占用非常有效
最后一個(gè)是局部加載, 并沒有怎么使用到,也不清楚就不說了
最后還有一個(gè)方法避免OOM, 開啟largeHeap屬性, 但是但是, 以前我們開啟這個(gè)屬性后被Oppo應(yīng)用市場(chǎng)認(rèn)定為占用內(nèi)存過高, 不建議用戶安裝......所以我們又取消了!
總的來說, Bitmap在內(nèi)存是變現(xiàn)的是不可控, 我項(xiàng)目OOM問題一直沒有得到有效解決,因?yàn)閳D片編輯視頻編輯之類的功能占用內(nèi)存過高,繼續(xù)使用OOM是必然的, 跟IOS的同學(xué)交流了一番,他們說IOS的應(yīng)用內(nèi)存可以占用到1個(gè)G以上, 輕松跑到500M是沒問題的, IOS的內(nèi)存機(jī)制可以持續(xù)給內(nèi)存使用, 具體我也不清楚,并且他們可以手動(dòng)釋放內(nèi)存?malloc, free這樣子?
如果大家有比較好的方案,還望留言交流互相幫助 [笑臉.gif]
補(bǔ)充: Android8.0開始Bitmap數(shù)據(jù)內(nèi)存存在native層, 單個(gè)應(yīng)用可用的內(nèi)存顯著增長(zhǎng), 極大的降低了OOM的概率(2018年3月22日)