android 內存優化相關知識點

1.內存的分配策略概述

程序運行時的內存分配有三種策略,分別是靜態的,棧式的,和堆式的,對應的,三種存儲策略使用的內存空間主要分別是靜態存儲區(也稱方法區)堆區棧區

  1. 靜態存儲區(方法區):內存在程序編譯的時候就已經分配好,這塊內存在程序整個運行期間都存在。它主要存放靜態數據、全局static數據和常量。
  2. 堆區:亦稱動態內存分配。程序在運行的時候用malloc或new申請任意大小的內存,程序員自己負責在適當的時候用free或delete釋放內存(Java則依賴垃圾回收器)。
  3. 棧區:在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。

可以引申出以下概念:

  1. 局部變量的基本數據類型和引用存儲於棧中,引用的對象實體存儲於堆中。因爲它們屬於方法中的變量,生命週期隨方法而結束。
  2. 成員變量全部存儲於堆中(包括基本數據類型,引用和引用的對象實體),因爲它們屬於類,類對象終究是要被new出來使用的。
  3. 我們所說的內存泄露,只針對堆內存,他們存放的就是引用指向的對象實體

2.產生內存泄漏的原因

在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(Garbage Collection,GC)完成的,程序員不需要通過調用函數來釋放內存,但它只能回收無用並且不再被其它對象引用的那些對象所佔用的空間,也隨之帶來了內存泄漏的可能。

雖然,我們有幾個函數可以訪問GC,例如運行GC的函數System.gc(),但是根據Java語言規範定義,該函數不保證JVM的垃圾收集器一定會執行。因爲不同的JVM實現者可能使用不同的算法管理GC。GC過程與對象的引用類型是嚴重相關的

以下就引出java中的引用類型(虛引用使用少,這裏不再介紹)

  1. 強引用:如果一個對象具有強引用,則垃圾回收器不會回收它,只有當進程結束的時候纔會回收它
    例如:Persion persion = new Perison(“張三”,27); 就是典型的強引用

  2. 弱引用:如果一個對象只具有弱引用,那麼在垃圾回收器線程掃描的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。
    例如:Persion persion = new Perison("張三", 27); WeakReference<Persion> weakReference = new WeakReference<>(persion); //將強引用對象置空後就只剩下弱引用 persion = null;

  3. 軟引用:如果一個對象只具有軟引用,則內存空間充足時,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以一直被程序使用
    例如:Persion persion = new Perison("張三", 27); SoftReference<Persion> softReference = new SoftReference<>(persion); //將強引用對象置空後就只剩下軟引用 persion = null;

    例如:假設我們在APP中加載大量的圖片,爲了節約用戶流量和提高用戶體驗,我們需要一般採用三級緩存,這裏需要大量的內存,很容易發生內存溢出(Out Of Memory 即OOM)的情況。這裏可以考慮使用軟引用或者弱引用來避免OOM。

    採用軟引用還是弱引用可參考該對象的使用頻率:
    如果該對象可能會經常使用的,就儘量用軟引用。如果該對象不被使用的可能性更大些,就可以用弱引用。

總結:內存泄漏的原因

堆內存中的長生命週期的對象持有短生命週期對象的強/軟引用,儘管短生命週期對象已經不再需要,但是因爲長生命週期對象持有它的引用而導致不能被回收,這就是Java中內存泄露的根本原因。

內存泄漏積累到一定程度就會引發OOM

那麼如何避免OOM呢

減小內存佔用:

  1. 使用更加輕量的數據結構:使用ArrayMap/SparseArray代替HashMap等傳統數據結構
  2. 避免在Android裏面使用枚舉類型(Enum)
  3. 減小Bitmap對象的內存佔用:解碼格式選擇RBG_565,選擇合適的縮放比例(inSampleSize)

內存對象的重複利用

  1. 注意在ListView/GridView/RecyclerView等出現大量重複子組件的視圖裏面對ConvertView的複用
  2. Bitmap對象的複用:在ListView/GridView/RecyclerView等顯示大量圖片的控件裏面需要使用LRU的機制來緩存處理好的Bitmap。
  3. 自定義View:避免在onDraw方法裏面執行對象的創建
  4. 避免在循環體裏面創建新對象
  5. StringBuilder和StringBuffer的使用:大量字符串拼接的時候String的“+”是很耗時的,其中StringBuilder線程不安全,StringBuffer線程安全

避免對象的內存泄露

  1. 考慮使用Application Context而不是Activity Context
  2. 注意臨時Bitmap對象的及時回收
  3. 注意監聽器的註銷
  4. 注意WebView的泄漏
  5. 注意Cursor對象是否及時關閉
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章