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