每個Android開發(fā)者必須知道的內(nèi)存管理知識

OOM.png

相信一步步走過來的Android從業(yè)者,每個人都會遇到OOM的情況。如何避免和防范OOM的出現(xiàn)个从,對于每一個程序員來說確實是一門必不可少的能力。今天我們就談談在Android平臺下內(nèi)存的管理之道,開始今天的主題之前嗦锐,先再次回顧兩個概念嫌松。

內(nèi)存泄漏:對象在內(nèi)存heap堆中中分配的空間,當不再使用或沒有引用指向的情況下奕污,仍不能被GC正澄幔回收的情況。多數(shù)出現(xiàn)在不合理的編碼情況下碳默,比如在 Activity中注冊了一個廣播接收器贾陷,但是在頁面關閉的時候進行unRegister,就會出現(xiàn)內(nèi)存溢出的現(xiàn)象嘱根。通常情況下髓废,大量的內(nèi)存泄漏會造成 OOM。

OOM:即OutOfMemoery该抒,顧名思義就是指內(nèi)存溢出了慌洪。內(nèi)存溢出是指APP向系統(tǒng)申請超過最大閥值的內(nèi)存請求,系統(tǒng)不會再分配多余的空間凑保,就會造成OOM error冈爹。在我們Android平臺下,多數(shù)情況是出現(xiàn)在圖片不當處理加載的時候愉适。

內(nèi)存管理之道嘛犯助,無非就是先理解并找出內(nèi)存泄漏的原因,再基于這些反式去合理的編碼维咸,去防范進而避免內(nèi)存開銷過大的情形剂买。學習如何合理的管理內(nèi)存,最好先 了解內(nèi)存分配的機制和原理癌蓖。只有深層次的理解了內(nèi)部的原理瞬哼,才能真正避免OOM的發(fā)生。但是本文就不介紹Jvm/Davilk內(nèi)存分配的機制了租副,如有興 趣坐慰,請查看歷史消息,以前做過題為《JVM運行時數(shù)據(jù)區(qū)域分析》的分享用僧。

Android APP的所能申請的最大內(nèi)存大小是多少结胀,有人說是16MB,有人又說是24MB责循。這種事情糟港,還是親自用自己的手機測試下比較靠譜。測試方式也比較簡 單院仿,Java中有個Runtime類秸抚,主要用作APP與運行環(huán)境交互速和,APP并不會為我們創(chuàng)建Runtime的實例,但是Java為我們提供了單例獲取的 方式Runtime.getRuntime()剥汤。通過maxMemory()方法獲取系統(tǒng)可為APP分配的最大內(nèi)存颠放,totalMemory() 獲取APP當前所分配的內(nèi)存heap空間大小。我手上有兩部手機吭敢,一部Oppo find7碰凶,運行Color OS,實測最大內(nèi)存分配為192MB省有;一部天語v9痒留,運行小米系統(tǒng),實測最大內(nèi)存分配為100MB蠢沿。這下看出點眉目了吧伸头,由于Android是開源系統(tǒng), 不同的手機廠商其實是擁有修改這部分權限能力的舷蟀,所以就造成了不同品牌和不同系統(tǒng)的手機恤磷,對于APP的內(nèi)存支持也是不一樣的,和IOS的恒久100MB是 不同的野宜。一般來說扫步,手機內(nèi)存的配置越高,廠商也會調(diào)大手機支持的內(nèi)存最大閥值匈子,尤其是現(xiàn)在旗艦機滿天發(fā)布的情況下河胎。但是開發(fā)者為了考慮開發(fā)出的APP的內(nèi) 存兼容性,無法保證APP運行在何種手機上虎敦,只能從編碼角度來優(yōu)化內(nèi)存了游岳。
下面我們逐條來分析Android內(nèi)存優(yōu)化的關鍵點。

1其徙、萬惡的static

static是個好東西胚迫,聲明賦值調(diào)用就是那么的簡單方便,但是伴隨而來的還有性能問題唾那。由于static聲明變量的生命周期其實是和APP的生命周期一 樣的访锻,有點類似與Application。如果大量的使用的話闹获,就會占據(jù)內(nèi)存空間不釋放期犬,積少成多也會造成內(nèi)存的不斷開銷,直至掛掉避诽。static的合理 使用一般用來修飾基本數(shù)據(jù)類型或者輕量級對象哭懈,盡量避免修復集合或者大對象,常用作修飾全局配置項茎用、工具類方法、內(nèi)部類。

2轨功、無關引用

很多情況下旭斥,我們需求用到傳遞引用,但是我們無法確保引用傳遞出去后能否及時的回收古涧。比如比較有代表性的Context泄漏垂券,很多情況下當Activity 結(jié)束掉后,由于仍被其他的對象指向?qū)е乱恢边t遲不能回收羡滑,這就造成了內(nèi)存泄漏菇爪。這時可以考慮第三條建議。

3柒昏、善用SoftReference/WeakReference/LruCache

Java凳宙、Android中有沒有這樣一種機制呢,當內(nèi)存吃緊或者GC掃過的情況下职祷,就能及時把一些內(nèi)存占用給釋放掉氏涩,從而分配給需要分配的地方。答案是 肯定的有梆,java為我們提供了兩個解決方案是尖。如果對內(nèi)存的開銷比較關注的APP,可以考慮使用WeakReference泥耀,當GC回收掃過這塊內(nèi)存區(qū)域時 就會回收饺汹;如果不是那么關注的話,可以使用SoftReference痰催,它會在內(nèi)存申請不足的情況下自動釋放兜辞,同樣也能解決OOM問題。同時 Android自3.0以后也推出了LruCache類陨囊,使用LRU算法就釋放內(nèi)存弦疮,一樣的能解決OOM,如果兼容3.0一下的版本蜘醋,請導入v4包胁塞。關于 第二條的無關引用的問題,我們傳參可以考慮使用WeakReference包裝一下压语。

4啸罢、謹慎handler

在處理異步操作的時候,handler + thread是個不錯的選擇胎食。但是相信在使用handler的時候扰才,大家都會遇到警告的情形,這個就是lint為開發(fā)者的提醒厕怜。handler運行于UI 線程衩匣,不斷處理來自MessageQueue的消息蕾总,如果handler還有消息需要處理但是Activity頁面已經(jīng)結(jié)束的情況下,Activity的 引用其實并不會被回收琅捏,這就造成了內(nèi)存泄漏生百。解決方案,一是在Activity的onDestroy方法中調(diào)用

handler.removeCallbacksAndMessages(null);取消所有的消息的處理柄延,包括待處理的消息蚀浆;二是聲明handler的內(nèi)部類為static。

5搜吧、Bitmap終極殺手

Bitmap的不當處理極可能造成OOM市俊,絕大多數(shù)情況都是因這個原因出現(xiàn)的。Bitamp位圖是Android中當之無愧的胖小子滤奈,所以在操作的時候當 然是十分的小心了摆昧。由于Dalivk并不會主動的去回收,需要開發(fā)者在Bitmap不被使用的時候recycle掉僵刮。使用的過程中据忘,及時釋放是非常重要 的。同時如果需求允許搞糕,也可以去BItmap進行一定的縮放勇吊,通過BitmapFactory.Options的inSampleSize屬性進行控制。 如果僅僅只想獲得Bitmap的屬性窍仰,其實并不需要根據(jù)BItmap的像素去分配內(nèi)存汉规,只需在解析讀取Bmp的時候使用 BitmapFactory.Options的inJustDecodeBounds屬性。最后建議大家在加載網(wǎng)絡圖片的時候驹吮,使用軟引用或者弱引用并進 行本地緩存针史,推薦使用android-universal-imageloader或者xUtils,牛人出品碟狞,必屬精品啄枕。前幾天在講《自定義控件(三) 繼承控件》的時候,也整理一個族沃,大家可以去Github下載看看频祝。

6、Cursor及時關閉

在查詢SQLite數(shù)據(jù)庫時脆淹,會返回一個Cursor常空,當查詢完畢后,及時關閉盖溺,這樣就可以把查詢的結(jié)果集及時給回收掉漓糙。

7、頁面背景和圖片加載

在布局和代碼中設置背景和圖片的時候烘嘱,如果是純色昆禽,盡量使用color蝗蛙;如果是規(guī)則圖形,盡量使用shape畫圖为狸;如果稍微復雜點歼郭,可以使用9patch圖;如果不能使用9patch的情況下辐棒,針對幾種主流分辨率的機型進行切圖。

8牍蜂、ListView和GridView的item緩存

對于移動設備漾根,尤其硬件參差不齊的android生態(tài),頁面的繪制其實是很耗時的鲫竞,findViewById也是蠻慢的辐怕。所以不重用View,在有列表的時候就尤為顯著了从绘,經(jīng)常會出現(xiàn)滑動很卡的現(xiàn)象寄疏。具體參照歷史文章《說說ViewHolder的另一種寫法》

9、BroadCastReceiver僵井、Service

綁定廣播和服務陕截,一定要記得在不需要的時候給解綁。

10批什、I/O流

I/O流操作完畢农曲,讀寫結(jié)束,記得關閉驻债。

11乳规、線程

線程不再需要繼續(xù)執(zhí)行的時候要記得及時關閉,開啟線程數(shù)量不易過多合呐,一般和自己機器內(nèi)核數(shù)一樣最好暮的,推薦開啟線程的時候,使用線程池淌实。

12冻辩、String/StringBuffer

當有較多的字符創(chuàng)需要拼接的時候,推薦使用StringBuffer翩伪。

今天沒有代碼微猖,純文字,純手打缘屹,蠻辛苦凛剥。整理了這么多優(yōu)化的策略,相信大家在理解后使用轻姿,再也不會遇上OOM了犁珠。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逻炊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子犁享,更是在濱河造成了極大的恐慌余素,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炊昆,死亡現(xiàn)場離奇詭異桨吊,居然都是意外死亡,警方通過查閱死者的電腦和手機凤巨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進店門视乐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人敢茁,你說我怎么就攤上這事佑淀。” “怎么了彰檬?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵伸刃,是天一觀的道長。 經(jīng)常有香客問我逢倍,道長捧颅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任瓶堕,我火速辦了婚禮隘道,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘郎笆。我一直安慰自己谭梗,他們只是感情好,可當我...
    茶點故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布宛蚓。 她就那樣靜靜地躺著激捏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凄吏。 梳的紋絲不亂的頭發(fā)上远舅,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天,我揣著相機與錄音痕钢,去河邊找鬼图柏。 笑死,一個胖子當著我的面吹牛任连,可吹牛的內(nèi)容都是我干的蚤吹。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裁着!你這毒婦竟也來了繁涂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤二驰,失蹤者是張志新(化名)和其女友劉穎扔罪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桶雀,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡矿酵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了矗积。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坏瘩。...
    茶點故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漠魏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妄均,我是刑警寧澤柱锹,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站丰包,受9級特大地震影響禁熏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜邑彪,卻給世界環(huán)境...
    茶點故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一瞧毙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寄症,春花似錦宙彪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至篮迎,卻和暖如春男图,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背甜橱。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工逊笆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人岂傲。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓难裆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親譬胎。 傳聞我的和親對象是個殘疾皇子差牛,可洞房花燭夜當晚...
    茶點故事閱讀 43,587評論 2 350

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