記憶體管理總覽

Android 執行階段 (ART) 和 Dalvik 虛擬機器使用情形 分頁 以及記憶體對應 (對應) 管理記憶體。這意味著 用於修改 新物件或輕觸對應的頁面,仍留在 RAM 中 無法分頁顯示。如果想從應用程式釋放記憶體,唯一的辦法就是釋出記憶體 物件參照應用程式保留,因此 我們計算了垃圾收集器 唯一例外的情況是,任何檔案 未顯示經過修改的程式碼,像是程式碼 如果系統想要在其他地方使用該記憶體,則可能需將 RAM 分頁至 RAM 以外的位置。

本頁面說明 Android 如何管理應用程式程序和記憶體配置。如要進一步瞭解如何更有效率地管理應用程式記憶體,請參閱「管理應用程式的記憶體」。

垃圾收集

在 Android 執行階段或 Dalvik 虛擬機器等受管理的記憶體環境中,系統會記錄每個記憶體配置。當系統判斷某段記憶體已經沒有程式使用時,就會將記憶體釋放回堆積,不需由程式設計人員操作。這個在受管理記憶體環境中收回未使用記憶體的機制,稱為「垃圾收集」。垃圾收集機制有兩大目標:找出程式中之後不供存取的資料物件,以及收回這些物件使用的資源。

Android 的記憶體堆疊分為不同代,也就是說,系統會根據所配置物件的預期生命和大小,追蹤不同的配置值區。舉例來說,最近配置的物件屬於「年輕代」。如果物件活躍時間夠長,就能升級到年老代,最後則是永久代。

每個堆疊代分別設有記憶體數量上限,規定物件能占用的記憶體數量。如果某一代即將達到上限,系統就會執行垃圾收集事件,嘗試釋放記憶體。垃圾收集時間長度取決於系統要收集的物件代,以及各代的活躍物件數量。

雖然垃圾收集速度可能相當快,但仍可能影響應用程式效能。一般來說,您無法在程式碼中控制垃圾收集事件的發生時機。系統會根據一系列的條件,決定何時執行垃圾收集事件。一旦符合條件,系統就會停止執行程序,並開始垃圾收集作業。如果垃圾收集事件發生在動畫或音樂播放等緊密的處理迴圈中,就可能拉長處理時間。時間拉長後,可能導致應用程式的程式碼執行作業超過建議的 16 毫秒門檻,造成影格轉譯效率不足或不夠順暢。

另外,程式碼流程可能會執行迫使垃圾收集事件更頻繁發生的工作,或導致垃圾收集時間比平常更長。舉例來說,如果在 Alpha 混合動畫每個影格的 for 迴圈最內層配置多個物件,就可能因大量物件對記憶體堆疊造成汙染。在這種情況下,垃圾收集器會執行多個垃圾收集事件,進而可能導致應用程式效能下降。

如果想進一步瞭解垃圾收集,請參閱「垃圾收集」。

分享記憶體

為透過 RAM 處理所有需要的項目,Android 會嘗試在多個程序間分享 RAM 頁面。執行方法如下:

  • 每個應用程式程序都會從現有程序 Zygote 中建立分支。當系統啟動,並載入常見架構程式碼及活動主題等資源時,Zygote 程序就會啟動。為了開始新的應用程式程序,系統會為 Zygote 程序建立分支,然後在新程序中載入並執行應用程式程式碼。這個方法可為架構程式碼和資源配置大部分的 RAM 頁面,讓所有應用程式程序共享這些頁面。
  • 大部分靜態資料會對應至一個程序。透過這項技術,不同程序可共享資料,也能視需要將資料分頁。靜態資料範例包括: Dalvik 代碼 (將代碼放在預先連結的 .odex 中) 用於直接對應的檔案)、應用程式資源 (將資源表格設計成 對齊 ZIP 檔案時 APK 項目) 和傳統專案 ,例如 .so 檔案中原生程式碼。
  • 在許多情況下,Android 會明確使用配置的共用記憶體區域 (ashmem 或 gralloc),在不同程序間分享相同的動態 RAM。舉例來說,視窗介面會使用應用程式和畫面合成器之間的共享記憶體,而游標緩衝區會使用內容供應器和用戶端之間的共享記憶體。

由於共享記憶體的用途相當豐富,請務必仔細判斷應用程式要使用多少記憶體。如要瞭解可妥善判斷應用程式記憶體用量的技術,請參閱有關調查 RAM 用量的說明文章。

配置及收回應用程式記憶體

在 Dalvik 堆積中,每個應用程式程序只能使用單一虛擬記憶體範圍。這會定義堆積的邏輯大小,這個大小可隨需求擴增,但需符合系統為每個應用程式定義的上限。

堆積的邏輯大小和堆積所使用的實體記憶體數量並不相同。Android 調查應用程式的堆積時,會算出稱為「比例集大小」(PSS) 的值,這個值代表與其他程序共享的骯髒頁面和乾淨頁面,但只會根據共享該 RAM 的應用程式數量按比例計算。系統會將這項 PSS 總數視為實體記憶體用量。如要進一步瞭解 PSS,請參閱有關調查 RAM 用量的指南。

Dalvik 堆積不會壓縮堆積的邏輯大小。也就是說,Android 不會透過重組堆積來凝聚空間。Android 只能在堆積末端出現未使用的空間時,縮減堆積的邏輯大小。不過,系統仍可縮減堆積所使用的實體記憶體。完成垃圾收集後,Dalvik 會逐步檢查堆積,找出未使用的頁面,然後使用 madvise 將這些頁面傳回核心。因此,為大型區塊建立配對的配置和取消配置時,應可收回所有 (或幾乎所有) 使用的實體記憶體。不過,如要從小型配置收回記憶體,效率可能會大幅下降,因為小型配置可能仍與其他尚未釋放的項目共用頁面。

限制應用程式記憶體

為維持正常運作的多工處理環境,Android 會為每個應用程式的堆積大小設定硬性限制。視裝置可提供的整體 RAM 數量而定,裝置的實際堆積大小限制會有所不同。如果應用程式已達到堆積容量上限,並嘗試配置更多記憶體,就可能收到 OutOfMemoryError

在某些情況下,例如為了判斷快取可安全保留多少資料,您可能會想查詢系統,找出目前裝置確切可用的堆積空間。您可以呼叫 getMemoryClass(),向系統查詢這項數值。這個方法會傳回整數,代表應用程式堆積可使用多少 MB。

切換應用程式

使用者切換應用程式時 Android 可確保應用程式 而是指使用者看不到、也不會在執行 音樂播放等前景服務 在快取中。 舉例來說,使用者首次啟動應用程式時,系統會為應用程式建立程序,但當使用者退出應用程式時,系統並「不會」退出程序,而會快取該程序。如果使用者稍後返回應用程式,系統就會重新使用該程序,加快應用程式切換速度。

如果應用程式具有快取程序,且會保留目前不需要的資源,那麼即便使用者未使用應用程式,仍會影響系統的整體效能。當記憶體等資源逐漸不足,系統就會終止快取中的程序。系統也會處理占用最多記憶體的程序,並可能終止這些程序來釋放 RAM。

注意:應用程式在快取中消耗的記憶體越少,就越不會遭到系統終止,且可以快速恢復運作。但視瞬間的系統需求而定,系統隨時可能終止快取的程序,無論資源用量多寡都一樣。

如要進一步瞭解程序在 是否在前景執行 Android 會自行決定 就可能會被終止,詳情請參閱 程序和執行緒 指南。

記憶體壓力測試

雖然高階裝置的記憶體壓力問題較不常見,但仍會造成問題 。請務必嘗試 重現這個記憶體壓力環境,以便編寫檢測設備測試來驗證應用程式 以及改善記憶體不足裝置的使用者體驗。

應用程式壓力測試

應用程式壓力測試 (stressapptest) 是一項記憶體介面測試,可協助建立真實的高負載情況,以便測試各種記憶體 和硬體限制還可以定義時間和記憶體限制 可讓您編寫檢測設備,以驗證高記憶體情境的實際體驗。 例如,您可以使用下列指令集來推送資料檔案系統中的靜態資料庫。 使其可執行,並執行 20 秒的 990 MB 壓力測試:
    adb push stressapptest /data/local/tmp/
    adb shell chmod 777 /data/local/tmp/stressapptest
    adb shell /data/local/tmp/stressapptest -s 20 -M 990

  

請參閱 stressapptest ,進一步瞭解安裝工具、常見引數和錯誤處理機制的說明文件 可能不準確或不適當

Straapptest 的觀察結果

stressapptest 等工具可用於要求大於任意空間的記憶體配置 廣告。這類要求可能會觸發各種快訊,您應留意 開發方向因記憶體可用性低而出發的三個主要快訊包括:
  • SIGABRT:由於要求配置 大於可用記憶體大小,而系統已處於記憶體壓力下,
  • SIGQUIT: 產生核心記憶體傾印,並在偵測到檢測設備測試時終止程序。
  • TRIM_MEMORY_EVENTS: 這些回呼適用於 Android 4.1 (API 級別 16) 以上版本,並提供詳細資料 方便您處理記憶體快訊