前言html
本文翻譯自Android開發者官網的一篇文檔,主要用於從宏觀上介紹內存管理須要注意的一些要點。android
中國版官網原文地址爲:https://developer.android.google.cn/topic/performance/memory-overview。程序員
路徑爲:Android Developers > Docs > 指南 > Best practies > Performance > Overview of memory management緩存
正文安全
Android運行時ART和Dalvik虛擬機使用分頁和內存映射(mmapping)管理內存。這意味着全部被修改過的內存——不管是經過分配新的對象仍是觸摸被映射的頁——仍然駐留在RAM中而且不能移除分頁。惟一從應用中釋放內存的方法是釋放應用持有的對象引用,讓內存可以被垃圾收集器使用。但有一個例外:若是系統想在其它地方使用內存,那麼全部被映射但沒有被修改的文件,好比代碼,可能會被從RAM的分頁中移除。app
本文將闡述Android如何管理應用進程和內存分配。更多關於如何更有效管理應用內存的信息,請查閱【管理應用的內存】。框架
垃圾收集ide
一個被管理的內存環境, 像ART或Dalvik虛擬機,保持追蹤每一塊內存分配。一旦虛擬機肯定某塊內存再也不被程序使用,它會釋放該內存回到堆中,而不須要程序員的任何干預。這個在被管理的內存環境中回收再也不被使用的內存的機制被稱爲垃圾收集。垃圾收集有兩個目標:找到程序中在將來不會再被訪問的數據對象;以及回收被那些對象使用的資源。性能
Android的內存堆是一個分代的內存堆,這意味着,基於被分配的對象的預期壽命和大小,它追蹤着不一樣的分配羣組。例如,最近被分配的對象屬於年輕代。當一個對象保持活躍了足夠長的時間,它可能會被提高到老年代,後面還有一個永久代。動畫
每個堆分代都有它本身的對象能夠佔據的特定的內存數量上限。任什麼時候候某代開始填充時,系統會執行一個垃圾回收事件來嘗試釋放內存。這個垃圾收集的持續時長取決於它所收集的對象在哪一個代,以及在每一個代中有多少活躍對象。
雖然垃圾收集可能很是快,但它仍然會影響您應用的性能。一般您沒法掌控代碼中垃圾收集事件什麼時候會發生。系統有一套正在運行的標準來決定什麼時候執行垃圾收集。當知足標準時,系統會中止執行進程並開始垃圾收集。若是垃圾收集發生在一個密集的正在處理的循環(如動畫或音樂回放期間)中間時,這可能會增長處理時間。這個增長可能潛在地推進應用中代碼執行時間超過爲有效和平滑幀渲染而建議的16ms閾值。
除此以外,您的代碼流可能執行某些類型的工做:這類工做強迫垃圾收集事件更頻繁地發生或者使它們延續得比日常時間更長。例如,若是在透明度混合動畫的每一幀期間,您在一個for循環最裏面部分分配多個對象,可能致使大量對象污染內存堆。在那種環境下,垃圾收集器會執行多個垃圾收集事件並會下降應用的性能。
更多關於垃圾收集的分代信息,請查閱【垃圾收集】。
共享內存
爲了適合在RAM中所須要的一切,Android嘗試跨進程分享RAM分頁。Android能夠經過以下方式實現這個目的:
由於共享內存的大量使用,肯定您的應用正在使用多少內存須要關注。關於正確肯定應用的內存使用,在【RAM使用研究】中進行探討。
分配和回收應用內存
對於每一個應用進程,Dalvik堆被限制爲單個虛擬內存範圍。這定義了邏輯堆的大小,這個大小能夠根據須要增加,但只能增加到系統爲每一個應用定義的極限值。
堆的邏輯大小和堆使用的物理內存數量並不相同。當檢查應用的堆時,Android會計算一個被稱爲Proportional Set Size(PSS),它會計算和其它進程共享的贓頁和乾淨頁——可是其數量只能與共享RAM的應用數成比例。PSS總數被系統當作是物理內存的足跡。更多關於PSS的信息,請查閱【RAM使用研究】指導。
Dalvik堆並不會壓縮堆的邏輯大小,這意味着Android不會整理堆碎片來壓縮空間。Android僅僅會在堆的結尾有未被使用的空間時壓縮邏輯堆大小。可是,系統仍然會減小被堆使用的物理內存。垃圾收集發生之後,Dalvik會遍歷堆而且找到未被使用的頁,而後使用madvise把那些頁返回到內核。因此,成對的分配和大塊的從新分配可能致使回收全部(或者幾乎全部)被使用的物理內存。但是,從小的分配中回收內存可能很是低效,由於用於小分配的頁面可能仍然和尚未被釋放的事物共享。
限制應用內存
爲了維護功能的多任務環境,Android對每一個應用的對大小設置了一個硬性限制。依據整體上所擁有的可用RAM數量多少,確切的堆大小限制在設備之間是不一樣的。若是您的應用已經到達了堆的容量而且嘗試分配更多的內存,可能會收到OutOfMemoryError。
在某些狀況下,您可能想查詢系統來確切地知道您當前的設備有多少可用的堆空間——例如,爲了肯定保留多少數據在緩存中是安全的。您能夠經過調用getMemoryClass()查詢系統來獲取這個數據。這個方法會返回一個整數來指示應用堆可用的兆字節數。
切換應用
當用戶在應用之間切換時,Android將不在前臺的應用——也就是,對用戶是不可見的或者運行一個前臺service如音樂播放——保存在最近最少使用(LRU)緩存中。例如,當用戶首先啓動應用,就會爲它建立一個進程;可是當用戶離開這個應用,那個進程並不會退出。系統會緩存這個進程。若是用戶稍後返回到該應用,系統會從新使用這個進程,從而讓應用切換得更快。
若是應用擁有一個緩存的進程,而且保留當前不須要的內存,那麼您的應用——即便當用戶不是正在使用它——會影響系統的總體性能。當系統運行時內存不足,系統會從最近最少使用的進程開始殺死LRU緩存中的應用。系統也會考慮那些持有最多內存的進程,而且可能終止它們來釋放RAM。
★ 注意:當系統開始殺死LRU緩存中的進程時,主要是從下往上進行的。系統也會考慮哪些進程消耗了更多的內存,而且這樣的話,若是被殺死能夠提供給系統更多的內存收穫。在LRU列表中消耗的內存越少,您保留在列表而且可以快速恢復的機會就越大。
更多關於當不在前臺運行時進程如何緩存以及Android如何決定哪些進程能夠被殺死的信息,請查閱【進程和線程】指導。
結語
本文最大限度保持原文的意思,因爲筆者水平有限,如有翻譯不許確或不穩當的地方,請指正,謝謝!