Android內存管理之道

    相信一步步走過來的Android從業者,每一個人都會遇到OOM的狀況。如何避免和防範OOM的出現,對於每個程序員來講確實是一門必不可少的能力。今天咱們就談談在Android平臺下內存的管理之道,開始今天的主題以前,先再次回顧兩個概念。java

    內存泄漏:對象在內存heap堆中中分配的空間,當再也不使用或沒有引用指向的狀況下,仍不能被GC正常回收的狀況。多數出如今不合理的編碼狀況下,好比在 Activity中註冊了一個廣播接收器,可是在頁面關閉的時候進行unRegister,就會出現內存溢出的現象。一般狀況下,大量的內存泄漏會形成 OOM。android

    OOM:即OutOfMemoery,顧名思義就是指內存溢出了。內存溢出是指APP向系統申請超過最大閥值的內存請求,系統不會再分配多餘的空間,就會形成OOM error。在咱們Android平臺下,多數狀況是出如今圖片不當處理加載的時候。程序員

    內存管理之道嘛,無非就是先理解並找出內存泄漏的緣由,再基於這些反式去合理的編碼,去防範進而避免內存開銷過大的情形。學習如何合理的管理內存,最好先 瞭解內存分配的機制和原理。只有深層次的理解了內部的原理,才能真正避免OOM的發生。可是本文就不介紹Jvm/Davilk內存分配的機制了,若有興 趣,請查看歷史消息,之前作過題爲《JVM運行時數據區域分析》的分享。算法

    Android APP的所能申請的最大內存大小是多少,有人說是16MB,有人又說是24MB。這種事情,仍是親自用本身的手機測試下比較靠譜。測試方式也比較簡 單,Java中有個Runtime類,主要用做APP與運行環境交互,APP並不會爲咱們建立Runtime的實例,可是Java爲咱們提供了單例獲取的 方式Runtime.getRuntime()。經過maxMemory()方法獲取系統可爲APP分配的最大內存,totalMemory() 獲取APP當前所分配的內存heap空間大小。我手上有兩部手機,一部Oppo find7,運行Color OS,實測最大內存分配爲192MB;一部天語v9,運行小米系統,實測最大內存分配爲100MB。這下看出點眉目了吧,因爲Android是開源系統, 不一樣的手機廠商實際上是擁有修改這部分權限能力的,因此就形成了不一樣品牌和不一樣系統的手機,對於APP的內存支持也是不同的,和IOS的恆久100MB是 不一樣的。通常來講,手機內存的配置越高,廠商也會調大手機支持的內存最大閥值,尤爲是如今旗艦機滿天發佈的狀況下。可是開發者爲了考慮開發出的APP的內 存兼容性,沒法保證APP運行在何種手機上,只能從編碼角度來優化內存了。數據庫

下面咱們逐條來分析Android內存優化的關鍵點。緩存

一、萬惡的static 網絡

    static是個好東西,聲明賦值調用就是那麼的簡單方便,可是伴隨而來的還有性能問題。因爲static聲明變量的生命週期實際上是和APP的生命週期一 樣的,有點相似與Application。若是大量的使用的話,就會佔據內存空間不釋放,聚沙成塔也會形成內存的不斷開銷,直至掛掉。static的合理 使用通常用來修飾基本數據類型或者輕量級對象,儘可能避免修復集合或者大對象,經常使用做修飾全局配置項、工具類方法、內部類。異步

二、無關引用 工具

    不少狀況下,咱們需求用到傳遞引用,可是咱們沒法確保引用傳遞出去後可否及時的回收。好比比較有表明性的Context泄漏,不少狀況下當Activity 結束掉後,因爲仍被其餘的對象指向致使一直遲遲不能回收,這就形成了內存泄漏。這時能夠考慮第三條建議。佈局

三、善用SoftReference/WeakReference/LruCache

    Java、Android中有沒有這樣一種機制呢,當內存吃緊或者GC掃過的狀況下,就能及時把一些內存佔用給釋放掉,從而分配給須要分配的地方。答案是 確定的,java爲咱們提供了兩個解決方案。若是對內存的開銷比較關注的APP,能夠考慮使用WeakReference,當GC回收掃過這塊內存區域時 就會回收;若是不是那麼關注的話,可使用SoftReference,它會在內存申請不足的狀況下自動釋放,一樣也能解決OOM問題。同時 Android自3.0之後也推出了LruCache類,使用LRU算法就釋放內存,同樣的能解決OOM,若是兼容3.0一下的版本,請導入v4包。關於 第二條的無關引用的問題,咱們傳參能夠考慮使用WeakReference包裝一下。

四、謹慎handler

    在處理異步操做的時候,handler + thread是個不錯的選擇。可是相信在使用handler的時候,你們都會遇到警告的情形,這個就是lint爲開發者的提醒。handler運行於UI 線程,不斷處理來自MessageQueue的消息,若是handler還有消息須要處理可是Activity頁面已經結束的狀況下,Activity的 引用其實並不會被回收,這就形成了內存泄漏。解決方案,一是在Activity的onDestroy方法中調用handler.removeCallbacksAndMessages(null);取消全部的消息的處理,包括待處理的消息;二是聲明handler的內部類爲static。

五、Bitmap終極殺手

    Bitmap的不當處理很可能形成OOM,絕大多數狀況都是因這個緣由出現的。Bitamp位圖是Android中當之無愧的胖小子,因此在操做的時候當 然是十分的當心了。因爲Dalivk並不會主動的去回收,須要開發者在Bitmap不被使用的時候recycle掉。使用的過程當中,及時釋放是很是重要 的。同時若是需求容許,也能夠去BItmap進行必定的縮放,經過BitmapFactory.Options的inSampleSize屬性進行控制。 若是僅僅只想得到Bitmap的屬性,其實並不須要根據BItmap的像素去分配內存,只需在解析讀取Bmp的時候使用 BitmapFactory.Options的inJustDecodeBounds屬性。最後建議你們在加載網絡圖片的時候,使用軟引用或者弱引用並進 行本地緩存,推薦使用android-universal-imageloader或者xUtils,牛人出品,必屬精品。前幾天在講《自定義控件(三)  繼承控件》的時候,也整理一個,你們能夠去Github下載看看。

六、Cursor及時關閉

    在查詢SQLite數據庫時,會返回一個Cursor,當查詢完畢後,及時關閉,這樣就能夠把查詢的結果集及時給回收掉。

七、頁面背景和圖片加載

    在佈局和代碼中設置背景和圖片的時候,若是是純色,儘可能使用color;若是是規則圖形,儘可能使用shape畫圖;若是稍微複雜點,可使用9patch圖;若是不能使用9patch的狀況下,針對幾種主流分辨率的機型進行切圖。

八、ListView和GridView的item緩存

    對於移動設備,尤爲硬件良莠不齊的android生態,頁面的繪製實際上是很耗時的,findViewById也是蠻慢的。因此不重用View,在有列表的時候就尤其顯著了,常常會出現滑動很卡的現象。具體參照歷史文章《說說ViewHolder的另外一種寫法》

九、BroadCastReceiver、Service

    綁定廣播和服務,必定要記得在不須要的時候給解綁。

十、I/O流

    I/O流操做完畢,讀寫結束,記得關閉。

十一、線程

    線程再也不須要繼續執行的時候要記得及時關閉,開啓線程數量不易過多,通常和本身機器內核數同樣最好,推薦開啓線程的時候,使用線程池。

十二、String/StringBuffer

    當有較多的字符創須要拼接的時候,推薦使用StringBuffer。

相關文章
相關標籤/搜索