什么是OOM
? ? ? 移動端內(nèi)存有限鼠证,手機(jī)給每個應(yīng)用分配大小有限(Google 源生OS分配的內(nèi)存為16M或者24M箫津,但是不同廠家的ROM會修改)诵冒。當(dāng)你使用的內(nèi)存空間接近閥值仙辟,實例化新對象雄右,需要分配新的內(nèi)存空間是。就會報Out of Memory巷送。
產(chǎn)生OOM的主要情況
1.同時加載大量大內(nèi)存對象驶忌。主要體現(xiàn)在加載大量Bitmap(如幀動畫、RecyclerView),內(nèi)存一下沖破閥值付魔,產(chǎn)生OOM聊品。
2.內(nèi)存泄露。內(nèi)存泄漏(Memory Leak)是指程序中己動態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放几苍,造成系統(tǒng)內(nèi)存的浪費翻屈,導(dǎo)致程序運行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。當(dāng)內(nèi)存泄露到一定的量妻坝,接近閥值的時候伸眶,再去new新對象時就會OOM。
OOM的監(jiān)測
查找內(nèi)存泄漏可以使用Android Studio 自帶的Android Profiler工具(Android Studio3.0之后不僅可以監(jiān)測內(nèi)存刽宪,還可以監(jiān)測CPU和network)厘贼,也可以使用Square產(chǎn)品的LeadCanary(帖一個使用說明地址http://www.reibang.com/p/7db231163168)。
ps:看過一個面試問題圣拄。OOM能不能try/catch ? try/catch可以避免這次報錯嘴秸,但是沒有真正處理內(nèi)存問題,還是可能再下一分配內(nèi)存的位置觸發(fā)售担。
OOM的解決方式
加載大量圖片
? 1. Bitmap壓縮赁遗。BitmapFactory,可以修改質(zhì)量族铆。比如把ARGB.8888改成RGB.565岩四,bitmap占用內(nèi)存會縮小一半(但是去掉了透明度,有些圖片沒法直接轉(zhuǎn)哥攘。Glide就默認(rèn)設(shè)置的是RGB.565)剖煌。Options.inSampleSize可以壓縮圖片比例。
? 2. 緩存逝淹。LruCache是常用的第三方框架的圖片緩存處理方式耕姊。LruCache使用一個LinkedHashMap簡單的實現(xiàn)內(nèi)存的緩存,沒有軟引用栅葡,都是強(qiáng)引用茉兰。如果添加的數(shù)據(jù)大于設(shè)置的最大值,就刪除最先緩存的數(shù)據(jù)來調(diào)整內(nèi)存欣簇。
? 3. 軟引用&弱引用规脸。當(dāng)一個對象只有軟引用的時候,如果內(nèi)存不足就會回收熊咽。當(dāng)一個對象只有弱引用的時候莫鸭,不管當(dāng)前內(nèi)存空間足夠與否,都會回收它的內(nèi)存横殴。不過被因,由于垃圾回收器是一個優(yōu)先級很低的線程, 因此不一定會很快發(fā)現(xiàn)那些只具有弱引用的對象。
? 4.替換.png圖片梨与。用較小的圖片替換.png堕花,比如jpg或者svg等。
內(nèi)存泄露
? ? 1.靜態(tài)變量導(dǎo)致內(nèi)存泄露蛋欣。如一個靜態(tài)變量持有當(dāng)前Activity對象(但是很少有人會這么干吧)航徙。
? ? 2.單例模式導(dǎo)致的內(nèi)存泄露如贷。單例模式的特點是它的生命周期與Application一致陷虎。所以單例模式實例化對象時,要用Application.context杠袱。
? ? 3.非靜態(tài)內(nèi)部類和匿名內(nèi)部類導(dǎo)致的內(nèi)存泄露尚猿。非靜態(tài)內(nèi)部類和匿名內(nèi)部類隱式持有外部類的引用。Handler經(jīng)常會不注意的時候?qū)懗赡涿麅?nèi)部類楣富,就造成內(nèi)存泄露凿掂。
? ? 4.資源未關(guān)閉導(dǎo)致的內(nèi)存泄露。資源性對象比如Cursor纹蝴,Stream庄萎、File文件等往往都用了一些緩沖,不使用的時候塘安,應(yīng)該及時關(guān)閉它們糠涛,否則會造成內(nèi)存泄漏。
? ? 5.屬性動畫導(dǎo)致的內(nèi)存泄露兼犯。屬性動畫中的無限循環(huán)動畫忍捡,如果沒有在onDestroy中停止,盡管界面上看不到動畫效果切黔,但是Activity還是被View持有砸脊,會導(dǎo)致內(nèi)存泄露。
? ? 6.集合容器導(dǎo)致內(nèi)存泄露纬霞。當(dāng)不需要對象時凌埂,并沒有把它的引用從集合中清理掉,也是一種內(nèi)存泄露诗芜。
一些相關(guān)的細(xì)節(jié)
? ? 1.StringBuffer瞳抓、StringBuilder和String一樣,也用來代表字符串绢陌。String類是不可變類挨下,任何對String的改變都會引發(fā)新的String對象的生成;StringBuffer脐湾、StringBuilder則是可變類臭笆,任何對它所指代的字符串的改變都不會產(chǎn)生新的對象。StringBuffer考慮了線程安全,StringBuilder沒有愁铺。但是單線程StringBuilder效率更高鹰霍。
? ? 2.內(nèi)存抖動是由于短時間內(nèi)有大量對象進(jìn)出新生代區(qū)導(dǎo)致的,它伴隨著頻繁的GC茵乱。如在view的OnDraw方法中實例化對象茂洒,或者在循環(huán)中實例化不必要的對象。內(nèi)存抖動可能會導(dǎo)致UI線程被頻繁阻塞瓶竭,畫面卡頓督勺。
總結(jié)
? ? OOM是同時加載大量大內(nèi)存圖片或者gc無法及時回收對象,達(dá)到內(nèi)存閥值之后的報錯斤贰。需要通過寫代碼時注意和后期監(jiān)測來避免智哀。