Android 初級(jí)探討 OOM問題 以及解決優(yōu)化之道

前言:本文章只是簡(jiǎn)單闡述實(shí)際開發(fā)中遇到的OOM 問題 本文不會(huì)涉及太多很深的技術(shù)點(diǎn),我也不懂,哈哈啊哈哈哈哈~

(一) 什么是OOM?

1: 這是一個(gè)面試官經(jīng)常會(huì)問到的問題

OOM就是內(nèi)存溢出,即Out Of Memory捶惜。也就是說申請(qǐng)的內(nèi)存超過了VM所分配的最大內(nèi)存;

這里我們簡(jiǎn)單闡述一個(gè)面試點(diǎn):? 內(nèi)存溢出(OOM)和內(nèi)存泄漏(memory leak)的區(qū)別 ?有好多剛?cè)雽W(xué)的童鞋一看"溢出","泄漏" ?哎呀!我擦!這不一個(gè)東西,其實(shí)不然,兩者還是存在很大的區(qū)別.

內(nèi)存溢出: ?簡(jiǎn)單舉個(gè)例子:,就好比哥幾個(gè)去按摩店 按摩 (請(qǐng)注意我這里指的是正規(guī)的按摩店,遙哥哥最近脖子疼,大家懂得.) ? 總共五個(gè)人,到店了,申請(qǐng)開房,然后服務(wù)員領(lǐng)著哥幾個(gè)去房間,打開房間一看, 我擦! 搞毛呢?五個(gè)人,你給我整四張床,然后服務(wù)員解釋道:"對(duì)不起,由于周末人多,目前只能給你們提供四人間" ........那另一個(gè)人躺門外啊,這就是溢出, ?就是你所需要的(內(nèi)存)超出了系統(tǒng)給你提供的(內(nèi)存).

內(nèi)存泄漏: 最后等了半天,換了五人間,躺好后,這脖子難受死了,這要趕緊叫中醫(yī)按摩師傅,五個(gè)人五個(gè)師傅,師傅來了后,按理說就該開始了,突然一個(gè)哥們側(cè)過身對(duì)我說"遙遙,我要換個(gè)技師",我一聽反問道:"換技師干嘛",這哥們吞吞吐吐說"這個(gè)不好看",我一聽大罵道"xxxx,按摩和技術(shù)長相有毛的關(guān)系?" 但話又說回來,其實(shí)我也沒相中,哈哈,沒辦法,自己請(qǐng)客,總得讓兄弟玩的開心吧,換就換吧,真是的...換了一個(gè)又一個(gè)人,我這一睜眼,屋里面站滿了人,這什么情況!!!!!! 我就和哥們說"你換就換,你換,你總得讓之前的回去吧,屋子本來就不大,師傅都站到外邊去了",哥們趕緊解釋道"我控幾不住我?guī)准鞍?總得讓我對(duì)比一下吧",遙遙表示翻了個(gè)白眼,這孩子真是宛如智障! 師傅都被擠到門外去了,這就是泄漏,就是你換了技師,你又不讓之前的回去,你申請(qǐng)內(nèi)存后,又無法釋放掉,久而久之就會(huì)造成內(nèi)存溢出(OOM)

咳咳....我絕對(duì)是正經(jīng)人,大家不要誤會(huì),好了簡(jiǎn)單說個(gè)知識(shí)點(diǎn),接下來我們言歸正傳......

上面我們已經(jīng)講了OOM產(chǎn)生的原因,要是想了解具體怎么產(chǎn)生的,為什么就超過了呢?這個(gè)大家可以去詳細(xì)了解下關(guān)于Android 內(nèi)存管理機(jī)制 ? Google在Android的官網(wǎng)上有一篇文章盗冷,初步介紹了Android是如何管理應(yīng)用的進(jìn)程與內(nèi)存分配;

(二)如何避免OOM總結(jié)

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

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

例如,我們可以考慮使用比較高效的ArrayMap/SparseArray而不是HashMap等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)得封。需要的同學(xué)可以去深入了解幾個(gè)的數(shù)據(jù)結(jié)構(gòu)和原理.這里不探討太深.

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

Bitmap的不當(dāng)處理極可能造成OOM埋心,絕大多數(shù)情況都是因這個(gè)原因出現(xiàn)的。Bitamp位圖是Android中當(dāng)之無愧的胖小子忙上,所以在操作的時(shí)候當(dāng)然是十分的小心了拷呆。由于Dalivk并不會(huì)主動(dòng)的去回收,需要開發(fā)者在Bitmap不被使用的時(shí)候recycle掉疫粥。使用的過程中茬斧,及時(shí)釋放是非常重要的。

項(xiàng)目中我們經(jīng)常會(huì)加載一些大圖片,有時(shí)候會(huì)一下加載很多,一張?jiān)趐c機(jī)上用的1024*768圖片梗逮,如果直接用在手機(jī)屏幕這種小屏幕上啥供,不僅沒有提高顯示質(zhì)量,還容易使內(nèi)存吃緊库糠。假設(shè)照片是用ARGB_8888格式伙狐,那么一張1024×768的圖片需要占用3M的內(nèi)存, 4-5張就OOM了瞬欧。bitmap分辨率越高贷屎,所占用的內(nèi)存就越大,這個(gè)是以2為指數(shù)級(jí)增長的艘虎。

解決方案:

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

decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8候生,存在很大差異同眯。

有時(shí)候我們用第三方框架的時(shí)候存在bug,在加載的圖片的時(shí)候回造成OMM問題,目前項(xiàng)目用的Glide遇到過這個(gè)問題,具體原因還待研究.

3)使用更小的圖片

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

?作為android適配 ?一般我們都會(huì)有四套資源圖片


?就目前而言,我們完全沒必要配置xxxhdpi 資源文件

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

1)RecycleView/GridView等item的緩存

? 1:convertView重用

ListView中的每一個(gè)Item顯示都需要Adapter調(diào)用一次getView()的方法柿估,這個(gè)方法會(huì)傳入一個(gè)convertView的參數(shù)循未,這個(gè)方法返回的View就是這個(gè)Item顯示的View。Android提供了一個(gè)叫做Recycler(反復(fù)循環(huán))的構(gòu)件秫舌,就是當(dāng)ListView的Item從滾出屏幕視角之外只厘,對(duì)應(yīng)Item的View會(huì)被緩存到Recycler中,相應(yīng)的會(huì)從生成一個(gè)Item舅巷,而此時(shí)調(diào)用的getView中的convertView參數(shù)就是滾出屏幕的緩存Item的View羔味,所以說如果能重用這個(gè)convertView,就會(huì)大大改善性能钠右。

? ?2:使用ViewHolder重用

?我們都知道在getView()方法中的操作是這樣的: 先從xml中創(chuàng)建view對(duì)象(inflate操作赋元,我們采用了重用convertView方法優(yōu)化),然后在這個(gè)view去findViewById飒房,找到每一個(gè)item的子View的控件對(duì)象搁凸,如:ImageView、TextView等狠毯。這里的findViewById操作是一個(gè)樹查找過程护糖,也是一個(gè)耗時(shí)的操作,所以這里也需要優(yōu)化嚼松,就是使用ViewHolder嫡良,把每一個(gè)item的子View控件對(duì)象都放在Holder中,當(dāng)?shù)谝淮蝿?chuàng)建convertView對(duì)象時(shí)献酗,便把這些item的子View控件對(duì)象findViewById實(shí)例化出來并保存到ViewHolder對(duì)象中寝受。然后用convertView的setTag將viewHolder對(duì)象設(shè)置到Tag中, 當(dāng)以后加載ListView的item時(shí)便可以直接從Tag中取出復(fù)用ViewHolder對(duì)象中的罕偎,不需要再findViewById找item的子控件對(duì)象了很澄。這樣便大大提高了性能。

避免對(duì)象的內(nèi)存泄露


內(nèi)存對(duì)象的泄漏颜及,會(huì)導(dǎo)致一些不再使用的對(duì)象無法及時(shí)釋放甩苛,這樣一方面占用了寶貴的內(nèi)存空間,很容易導(dǎo)致后續(xù)需要分配內(nèi)存的時(shí)候俏站,空閑空間不足而出現(xiàn)OOM讯蒲。

1)注意Activity的泄漏

通常來說,Activity的泄漏是內(nèi)存泄漏里面最嚴(yán)重的問題乾翔,它占用的內(nèi)存多爱葵,影響面廣施戴,我們需要特別注意以下兩種情況導(dǎo)致的Activity泄漏:

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

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

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

內(nèi)部類引起的泄漏不僅僅會(huì)發(fā)生在Activity上,其他任何內(nèi)部類出現(xiàn)的地方而姐,都需要特別留意腊凶!我們可以考慮盡量使用static類型的內(nèi)部類,同時(shí)使用WeakReference的機(jī)制來避免因?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)過變換得到新的bitmap對(duì)象之后官帘,應(yīng)該盡快回收原始的bitmap蟹略,這樣能夠更快釋放原始bitmap所占用的空間。

4)注意WebView的泄漏

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

內(nèi)存使用策略優(yōu)化

1)資源文件需要選擇合適的文件夾進(jìn)行存放

我們知道hdpi/xhdpi/xxhdpi等等不同dpi的文件夾下的圖片在不同的設(shè)備上會(huì)經(jīng)過scale的處理稍刀。例如我們只在hdpi的目錄下放置了一張100100的圖片撩独,那么根據(jù)換算關(guān)系敞曹,xxhdpi的手機(jī)去引用那張圖片就會(huì)被拉伸到200200。需要注意到在這種情況下综膀,內(nèi)存占用是會(huì)顯著提高的澳迫。對(duì)于不希望被拉伸的圖片,需要放到assets或者nodpi的目錄下剧劝。

2)Try catch某些大內(nèi)存分配的操作

在某些情況下橄登,我們需要事先評(píng)估那些可能發(fā)生OOM的代碼,對(duì)于這些可能發(fā)生OOM的代碼讥此,加入catch機(jī)制拢锹,可以考慮在catch里面嘗試一次降級(jí)的內(nèi)存分配操作。例如decode bitmap的時(shí)候萄喳,catch到OOM卒稳,可以嘗試把采樣比例再增加一倍之后,再次嘗試decode他巨。

3)謹(jǐn)慎使用static對(duì)象

因?yàn)閟tatic的生命周期過長充坑,和應(yīng)用的進(jìn)程保持一致,使用不當(dāng)很可能導(dǎo)致對(duì)象泄漏闻蛀,在Android中應(yīng)該謹(jǐn)慎使用static對(duì)象

4)及時(shí)釋放無用的對(duì)象,尤其是循環(huán)內(nèi)的對(duì)象要及時(shí)釋放

5):優(yōu)化代碼,更高效的邏輯處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匪傍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子觉痛,更是在濱河造成了極大的恐慌役衡,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件薪棒,死亡現(xiàn)場(chǎng)離奇詭異手蝎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)俐芯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門棵介,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吧史,你說我怎么就攤上這事邮辽。” “怎么了贸营?”我有些...
    開封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵吨述,是天一觀的道長。 經(jīng)常有香客問我钞脂,道長揣云,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任冰啃,我火速辦了婚禮邓夕,結(jié)果婚禮上刘莹,老公的妹妹穿的比我還像新娘。我一直安慰自己焚刚,他們只是感情好点弯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著汪榔,像睡著了一般蒲拉。 火紅的嫁衣襯著肌膚如雪肃拜。 梳的紋絲不亂的頭發(fā)上痴腌,一...
    開封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音燃领,去河邊找鬼士聪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛猛蔽,可吹牛的內(nèi)容都是我干的剥悟。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼曼库,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼区岗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起毁枯,我...
    開封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤慈缔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后种玛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體藐鹤,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年赂韵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娱节。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祭示,死狀恐怖肄满,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情质涛,我是刑警寧澤稠歉,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站蹂窖,受9級(jí)特大地震影響轧抗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞬测,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一横媚、第九天 我趴在偏房一處隱蔽的房頂上張望纠炮。 院中可真熱鬧,春花似錦灯蝴、人聲如沸恢口。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耕肩。三九已至,卻和暖如春问潭,著一層夾襖步出監(jiān)牢的瞬間猿诸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來泰國打工狡忙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梳虽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓灾茁,卻偏偏與公主長得像窜觉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子北专,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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