Android內存管理機制

  • Android內存的意義
  • Android進程種類
    • 前臺進程(foreground)
    • 可見進程(visible)
    • 桌面進程(home app)
    • 次要服務(secondary server)
    • 後臺進程(hidden)
    • 內容供應節點(content provider)
    • 空進程(empty)
  • 垃圾內存回收算法
    • 引用計數回收法(Reference Counting GC)
    • 根搜索算法
      • 標註並清理回收法(Mark and Sweep GC)
      • 標註並整理回收法(Mark and COMPACT GC)
      • 拷貝回收法(Copying GC)
    • 逐代回收法(Generational GC)
  • Android內存管理源碼分析

Android內存的意義

  在使用安卓系統手機的時候我們並不用太在意所剩餘內存:
  由於Android上的應用是java,所以需要虛擬機,並且Android上的應用是帶有獨立虛擬機的,也就是說每開一個Android應用同時就會爲該應用打開一個獨立的虛擬機。而Android與linux的區別在於:
  1.Linux在進程活動停止後就結束該進程,
  2.Android在進程活動停止後,並沒有結束該進程,而是將進程都保留在內存中。
  所以Android和java的垃圾回收機制類似,系統有一個規則來回收內存。進行內存的調度有一個閥值,只有當可用閥值低於這個值時系統纔會按該規則來關閉用戶不需要的東西,但事實上他並不影響速度,相反加快了下次啓動應用的速度(內存讀寫的高速特性)。這本來就是 android標榜的優勢之一,如果人爲去關閉進程,沒有太大必要。至於說內存少的時候運行大型程序會變慢,那是因爲:在內存剩餘不多時打開大型程序時會觸發系統自身的調進程調度策略,該調度是個十分消耗系統資源的操作,尤其是在一個程序頻繁向系統申請內存的時候。這種情況下系統並不會關閉所有打開的進程,而是選擇性關閉,頻繁的調度自然會拖慢系統。

Android進程種類

前臺進程(foreground)

  目前正在屏幕上顯示的進程和一些系統進程,即可能用戶當前正在通過該進程與系統進行交互,所以該進程爲最重要的進程,除非系統的內容已經到不堪重負的情況,否則系統是不會將改進程終止的,舉例來說,Dialer,Storage,Google Search等系統進程就是前臺進程;再舉例來說,當你運行一個程序,如瀏覽器,當瀏覽器界面在前臺顯示時,瀏覽器屬於前臺進程(foreground),但一旦你按home回到主界面,瀏覽器就變成了後臺程序(background)。我們最不希望終止的進程就是前臺進程。

可見進程(visible)

  可見進程是一些不再前臺,但用戶依然可見的進程,舉個例來說:widget、輸入法等,都屬於visible。這部分進程雖然不在前臺,但與我們的使用也密切相關,我們也不希望它們被終止(你肯定不希望時鐘、天氣,新聞等widget被終止,那它們將無法同步,你也不希望輸入法被終止,否則你每次輸入時都需要重新啓動輸入法)

桌面進程(home app)

  即launcher,保證在多任務切換之後,可以快速返回到home界面而不需重新加載launcher

後臺進程(hidden)

  即是後臺進程(background),就是我們通常意義上理解的啓動後被切換到後臺的進程,如瀏覽器,閱讀器等。當程序顯示在屏幕上時,他所運行的進程即爲前臺進程(foreground),一旦我們按home返回主界面(注意是按home,不是按back),程序就駐留在後臺,成爲後臺進程(background)。後臺進程的管理策略有多種:有較爲積極的方式,一旦程序到達後臺立即終止,這種方式會提高程序的運行速度,但無法加速程序的再次啓動;也有較消極的方式,儘可能多的保留後臺程序,雖然可能會影響到單個程序的運行速度,但在再次啓動已啓動的程序時,速度會有所提升。這裏就需要用戶根據自己的使用習慣找到一個平衡點

次要服務(secondary server)

  目前正在運行的一些服務(主要服務,如撥號等,是不可能被進程管理終止的,故這裏只談次要服務),舉例來說:谷歌企業套件,Gmail內部存儲,聯繫人內部存儲等。這部分服務雖然屬於次要服務,但很一些系統功能依然息息相關,我們時常需要用到它們,所以也太希望他們被終止

內容供應節點(content provider)

  沒有程序實體,進提供內容供別的程序去用的,比如日曆供應節點,郵件供應節點等。在終止進程時,這類程序應該有較高的優先權

空進程(empty)

  沒有任何東西在內運行的進程,有些程序,比如BTE,在程序退出後,依然會在進程中駐留一個空進程,這個進程裏沒有任何數據在運行,作用往往是提高該程序下次的啓動速度或者記錄程序的一些歷史信息。這部分進程無疑是應該最先終止的。

垃圾內存回收算法

引用計數回收法(Reference Counting GC)

原理:即記錄每個對象被引用的次數。每當創建一個新的對象,或者將其它指針指向該對象時,引用計數都會累加一次;而每當將指向對象的指針移除時,引用計數都會遞減一次,當引用次數降爲0時,刪除對象並回收內存。採用這種算法比較出名的框架有微軟的COM框架。
關係圖如下:
圖1 引用計數與對象實例關係圖
通常對象的引用計數都會跟對象放在一起,系統在分配完對象的內存後,返回的對象指針會跳過引用計數部分。
以下示例演示了一個對象引用計數的增減方式。

Object obj1 = new Object();// obj1的引用計數爲1
Object obj2 = obj1;// obj2指針指向obj1,所以obj1的引用計數爲2
Object obj3 = new Object();

obj2 = null; // obj1的引用計數遞減1次爲1。
obj1 = obj3; // obj1的引用計數遞減1次爲0,可以回收其內存。

缺點:無法有效處理循環引用的問題

根搜索算法

原理:程序在運行的過程中會不停的創建新的對象並消耗內存,直到內存用光,這時如果需要再創建新的對象時,系統暫停其它組件的運行,並觸發GC線程啓動垃圾回收過程。該過程即:從”GC Roots”集合開始,遍歷一次內存,然後保留所有可以被GC Roots直接或間接引用到的對象,而剩下的對象則都當作垃圾對待並回收。並且在根搜索算法的基礎上,現代虛擬機的實現當中,垃圾蒐集的算法主要分有三種:標註並清理回收法、標註並整理回收法、拷貝回收法
回收內存垃圾之前的對象引用關係
回收內存垃圾之前的對象引用關係
即當前內存中存在A、B、C、D、E、F、G、H八個對象

標註並清理回收法(Mark and Sweep GC)

1.標記:即在執行”GC Roots”遍歷時,找出所有被直接或者間接引用着的對象並做上標記
2.清理:清除遍歷堆中所有未被標記的對象。
3.缺點:
  3.1:效率比較低(遞歸與全堆對象遍歷),而且在進行GC的時候,需要停止應用程序,這會導致用戶體驗非常差勁,尤其對於交互式的應用程序來說簡直是無法接受。
  3.2:清理出來的空閒內存是不連續的
如下圖2:GC線程標識出所有不能被回收的對象實例
這裏寫圖片描述
執行完”GC Roots”遍歷之後發現,只有A、B、C、D、H五個對象被“GC Roots直接或者間接引用着,其餘就會被當做垃圾進行回收

標註並整理回收法(Mark and COMPACT GC)

1.標記:標註並清理回收法一樣,均是遍歷GC Roots,然後將存活的對象標記。
2.整理:如圖2中標記的存活對象,移動所有存活的對象,且按照內存地址次序依次排列,然後將末端內存地址以後的內存全部回收。因此,第二階段才稱爲整理階段。

拷貝回收法(Copying GC)
逐代回收法(Generational GC)

Android內存管理源碼分析

Android源碼,可以在網址:http://androidxref.com/source/xref/ 中在線瀏覽。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章