在之前的文章中我們總結過跟Android 內存相關的知識或者問題,這里先列舉一下:
2. Java 對象引用方式 —— 強引用、軟引用、弱引用和虛引用
3. Android Studio 使用Memory Monitor進行內存泄露分析
5. Android 常見 Memory Leak 原因及解決辦法總結
從之前整理的內存來看,我們首先需要了解的就是Java內存使用及回收相關的知識,然后在Android上涉及內存管理問題主要就是內存抖動、內存泄漏、內存溢出。
本文我們針對性能優化再次做一下Android開發時我們能對內存方面進行優化的內容,雖然有點贅述,但是希望能溫故知新。
首先我們先了解一下Android的內存分配策略,然后再談一下如何優化內存問題。
一、Android 內存策略
1. Android 進程的內存策略
進程的內存分配策略為:由 ActivityManagerService
集中管理所有進程的內存分配。
進程的內存回收策略為:
首先 Application Framework 決定回收的類型,當進程的內存空間緊張時會按照進程優先級由低到高的順序自動回收進程及內存。
Android Framework將進程分為5個優先級,具體如下:
真正執行回收進程的操作的是 Linux 內核。
梳理一下整體流程:
1. ActivityManagerService 對所有進程進行評分。
2. 更新評分到 Linux 內核。
3. 由 Linux 內核完成真正的內存回收。
2. Android 對象、變量的內存策略
Android 對對象、變量的內存策略和Java是一樣的,對內存的管理即為 對象&變量的內存分配和內存釋放。下面我們講一下內存分配和內存釋放的策略:
a. 內存分配策略
對象&變量的內存分配有系統負責,共有三種:靜態分配、棧式分配、堆式分配,分別面向靜態變量,動態變量和對象實例。
b. 內存釋放策略
對象&變量的內存釋放由Java的垃圾回收器GC負責。
二、常見的內存問題及優化方案
常見的內存問題如下: 內存抖動、內存泄漏、內存溢出。
1. 內存泄漏
內存泄漏的定義是:內存中存在已經不再使用,但是並未回收的對象。表現的現象為:內存出現抖動和可用內存逐漸變少。存在的危害是:會造成內存不足,GC頻繁,甚至出現OOM。
常見引發內存泄漏的主要情況有如下情況:
1. static 關鍵字修飾的成員變量
核心點:被static修飾過的成員變量的生命周期 = 應用程序的生命周期。
泄漏原因:若被static修飾的成員變量引用短生命周期的實例,則容易出現該成員變量的生命周期 > 引用實例生命周期的情況,當引用實例需結束生命周期銷毀時,會因靜態變量的持有而無法被回收,從而出現內存泄露。
解決方案:
a. 盡量避免static成員變量引用資源消耗過多的實例(若需引用Context,則盡量使用Application的Context)。
b. 使用弱引用WeakReference代替強引用持有實例。
經典案例 ==》單例模式
核心點:單例模式 其生命周期的長度 = 應用程序的生命周期
泄漏原因:若1個對象已不需再使用 而單例對象還持有該對象的引用,那么該對象將不能被正常回收 從而 導致內存泄漏
解決方案:單例模式引用的對象的生命周期 = 應用的生命周期。 或者編寫代碼保證在合適的時機釋放資源。
2. 非靜態內部類/匿名類
核心點:非靜態內部類默認持有外部類的引用,可能會導致外部類對象無法釋放,造成內存泄漏。
解決方案:使用靜態內部類。
經典案例 ==》Runnable、AsyncTask、Thread、Handler 等類
3. 資源使用后未關閉
泄露原因:對於資源的使用(如 廣播BraodcastReceiver
、文件流File
、數據庫游標Cursor
、),若在Activity
銷毀時沒有及時關閉或注銷這些資源,則這些資源將不會被回收,從而造成內存泄漏。
Activity
銷毀時 及時關閉 / 注銷資源

2. 內存抖動
核心原因:頻繁創建大量、臨時的小對象。
排查方向:優先尋找循環或者頻繁調用的地方進行排查。
優化方案:避免創建大量、臨時的小對象。
3. 內存溢出
請參考:Android OOM 引發的思考。這里就不過多整理了。