1、定義
- 定義:內存不在使用,無法歸還給應用程序的現象。
2、影響
- 影響:容易使應用程序發生內存溢出(Out Of Memory )。OOM(定義:應用程序所需內存 大於 安卓系統分配的內存);安卓系統爲每個應用程序分配的內存有限,內存溢出容易導致應用程序崩潰。
3、原因
- 本質原因:持有引用者的生命週期 大於 被引用者的生命週期。導致本該回收的對象無法被回收。
4、Android 內存管理機制
- 定義:Android 內存管理:內存分配 和 內存回收。
- 管理的對象:進程、對象、變量。
- 管理的角色:Application Framework、Dalvik 虛擬機、Linux 內核。Application Framework 和 Linux 內核 負責 進程;Dalvik 虛擬機 負責 對象、變量 內存管理。
- 進程的內存分配與回收
1、分配:ActivityManagerService 管理進程的內存分配。
2、回收:1.Application Framework 按優先級決定回收類型(前臺進程>可見進程>服務進程>後臺進程>空進程)。2.Linux 內核回收具體進程。 - 對象、變量的內存分配與回收
內存分配策略 | 使用內存空間 | 存儲數據 | 特點 |
---|---|---|---|
靜態分配 | 方法區 | 類信息、常量、靜態變量 | 1.編譯時分配好。2.存在整個程序的運行區間。 |
棧分配 | 棧區 | 局部變量(基本數據類型、對象的引用) | 1.方法執行時,程序自動在棧中分配內存,方法結束,自動釋放內存。2.效率高。3.內存容量有限。 |
堆分配 | 堆區 | 對象的實例、實例的成員變量 | 1.創建對象,程序在堆中分配內存。2.Java 垃圾回收器(垃圾回收算法),回收內存 |
算法名稱 | 算法思想 | 優點 | 缺點 | 應用場景 |
---|---|---|---|---|
標記-清除 算法 | 1.標記階段:標記出所以要回收的對象。2.清除階段:清除所以被標記的對象。 | 實現簡單 | 1.效率問題:標記 和 清除 兩個過程,效率低。2.空間問題:產生大量不連續的內存碎片。 | 對象存活率高;垃圾回收頻率低。(如:老年代) |
複製 算法 | 1.將內存分爲大小相等的兩塊,每次使用其中的一塊。2.當使用的這塊內存用完,將還存活的對象複製到另一塊內存。3.最後將使用的那塊內存一次性清理掉。 | 1.解決標記-清除效率問題:每次回收內存一半區域。2.解決標記-清除空間問題:將存活對象按順序複製到另一塊內存。 | 1.每次使用的內存縮小爲原來一半。2.對象存活率高的情況要做較多複製操作,效率低。 | 對象存活率低;垃圾回收頻率高。(如:新生代) |
標記-整理 算法 | 1.標記階段:標記出所以要回收的對象。2.整理階段:讓所有存活的對象都向一端移動。3.清除階段:清除所以被標記的對象。 | 1.解決標記-清除效率問題:一次清除端外區域。2.解決標記-清除空間問題:存活的對象移到一端。 | 步驟繁瑣:標記、整理、清除。 | 對象存活率高;垃圾回收頻率低。(如:老年代) |
分代回收 算法 | 根據對象的存活週期將堆內存分爲:新生代和老年代。1.新生代:對象存活率低;垃圾回收頻率高。採用 複製算法。2.老年代:對象存活率高;垃圾回收頻率低。採用 標記-清除、標記-整理 算法。 | 效率高,空間利用率高:根據不同區域特點選擇不同垃圾回收算法 | 虛擬機採用此算法 |
如何判斷一個對象是否可以被回收:
1、引用計數算法:引用計數爲 0 的對象實例可以被當作垃圾回收。(很難解決對象相互引用的問題)。
2、可達性分析算法:不可到達的對象表示可以回收。
5、常見內存泄漏原因及解決方案
1、集合類
2、static 關鍵字修飾成員變量
3、非靜態內部類 / 匿名類
4、資源對象使用後未關閉
5、其它(Context、WebView、Adapter)
- 集合類
1、原因:集合添加元素,引用了該元素對象,導致對象不可以被回收,導致內存泄漏。
2、解決方案:集合使用後清除對象。(如:list.clear();list = null ;) - static 關鍵字修飾成員變量
1、原因:static 修飾的生命週期 = 應用程序的生命週期。(如:static Context = mContext;)
2、解決方案:1、使用 Application 的 Context。2、使用弱引用(WeakReference)。 - 非靜態內部類 / 匿名類
1、原因:非靜態內部類 / 匿名類 默認持有外部類的引用。
2、解決方案:1、使用 Application 的 Context。2、使用弱引用(WeakReference)。3、使用靜態內部類。(如:多線程 Thread、Handler 等)。 - 資源對象使用後未關閉
1、原因:資源對象使用後未關閉,資源將不會被回收,導致內存泄漏。
2、解決方案: 資源對象使用後關閉。(如:廣播 BroadcastReceiver-unregisterReceiver()、文件流-InputStream.close()、數據庫遊標 Cursor-Cursor.close、圖片資源 Bitmap-Bitmap.recycle();Bitmap = null;、動畫停止)。 - 其它(Context、WebView、Adapter)
1、Context:使用 Application 的 Context;使用弱引用。
2、WebView:動態創建 WebView;不使用時銷燬。
3、Adapter:如 ListView:使用緩存 convertView;使用 ViewHolder。或 RecycleView 替代。
5、輔助分析內存泄漏
- Android Profiler:Androidstudio 3.0自帶工具,分析 CPU、MEMORY、NETWORK 等。
- LeakCanary:Square 出品的檢測內存泄漏的開源庫。