Android——內存管理基礎

動態內存

《深入理解計算機系統》對動態內存分配器的定義是:維護着一個進程的虛擬存儲器區域,成爲”堆“,對於每一個進程,操作系統內核維護着一個變量brk(break)指向堆的頂部。

下面給出我關於動態內存分配方面的理解:

動態內存分配器,我的理解就是在程序執行的過程當中,動態的分配或釋放虛擬內存。

有了動態內存分配的概念,自然就會有動態存儲器的概念。所謂動態存儲器,簡而言之就是我們進程虛擬內存中的堆。堆在動態內存分配的過程中,會動態的增長或減少。堆在虛擬進程的結構當中是向上增長的,當堆內存不夠時,還可以向操作系統請求額外的內存。

動態存儲器分配器有兩種基本分格:

  • 顯式分配器:顯示分配內存,顯示釋放內存。例如C和C++的malloc或者new分配內存,但是需要程序員顯示調用free或者delete釋放內存。
  • 隱式分配器:也叫做垃圾收集器,顯示分配內存,自動釋放未使用的已分配的塊的過程叫做垃圾收集。例如:Java的垃圾回收機制。

垃圾收集器(garbage collector)

概念:自動的內存管理:顯示地分配堆內存,隱式地釋放堆內存。

功能:

  1. 分配堆內存
  2. 保證所有被引用的對象還在堆內存中
  3. 可以釋放在運行的代碼中不再引用的對象的堆內存

垃圾收集器避免了懸掛指針(dangling reference),原因是一個仍然被引用的對象永遠不會內存回收並且也不會被認爲已經被釋放掉了。

垃圾收集器解決了空間泄漏(space leaks)問題,原因是它可以自動釋放不再被引用的空間。

垃圾(garbage)

如果對象被引用着,那我們說它活着(live);如果對象不再被引用了,那我們說他死了(dead),術語稱作垃圾(garbage)。

垃圾收集(garbage collection)

尋找並釋放這些對象的空間的過程就做垃圾收集(garbage collection)。那麼在什麼時候會出發垃圾收集動作呢?一般來說整個堆或一部分被填滿或者達到某一百分比數值時將被收集。

常見的三種垃圾收集器

串行(Serial):也被稱爲完全停頓(Stop-the-world)。當執行GC時,程序的線程都會被掛起。

並行(Parallel):圾收集工作被分成幾部分,這些子部將會在不同的CPU上被同時執行。同時執行會使垃圾收集得更快,但是代價是會增加複雜性和潛在碎片。

併發(Concurrent):一個或者多個垃圾收集任務也可以併發的與應用程序同時執行。通常,一個併發收集器可以併發的執行垃圾收集的大部分工作,但是也會不可避免的引發一個小的停頓。

Android Garbage Collector發展

Android 1.0~2.2,Dalvik虛擬使用的垃圾收集機制有以下特點:

  1. Stop-the-word(完全停頓),也就是一個垃圾收集線程在執行的時候,其它的線程都停止;
  2. Full heap collection,也就是一次收集完全部的垃圾;
  3. 長等待,一次垃圾收集造成的程序中止時間通常都大於100ms。

Android 2.3~至今,Dalvik虛擬使用的垃圾收集機制得到了改進

  1. Cocurrent(併發),也就是大多數情況下,一個或多垃圾收集線程與其它線程是併發執行的;
  2. Partial collection,也就是一次可能只收集一部分垃圾;
  3. 短等待,一次垃圾收集造成的程序中止時間通常都小於5ms。

Dalvik虛擬機執行完成一次垃圾收集之後,我們通常可以看到類似以下的日誌輸出:

D/dalvikvm(9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms

在這一行日誌中,GC_CONCURRENT表示GC原因,2049K表示總共回收的內存,3571K/9991K表示Java Object Heap統計,即在9991K的Java Object Heap中,有3571K是正在使用的,4703K/5261K表示External Memory統計,即在5261K的External Memory中,有4703K是正在使用的,2ms+2ms表示垃圾收集造成的程序中止時間。

Android內存管理

Dalvik虛擬機的內存大體上可以分爲Java Object Heap、Bitmap Memory和Native Heap三種。

Java Object Heap

Java Object Heap是用來分配Java對象的,也就是我們在代碼new出來的對象都是位於Java Object Heap上的。

Dalvik虛擬機在啓動的時候,可以通過-Xms和-Xmx選項來指定Java Object Heap的最小值和最大值。爲了避免Dalvik虛擬機在運行的過程中對Java Object Heap的大小進行調整而影響性能,我們可以通過-Xms和-Xmx選項來將它的最小值和最大值設置爲相等。

Java Object Heap的最小和最大默認值爲2M和16M,但是手機在出廠時,廠商會根據手機的配置情況來對其進行調整,例如,G1、Droid、Nexus One和Xoom的Java Object Heap的最大值分別爲16M、24M、32M 和48M。我們可以通過ActivityManager類的成員函數getMemoryClass來獲得Dalvik虛擬機的Java Object Heap的最大值。

ActivityManager類的成員函數getMemoryClass的實現如下所示:

public class ActivityManager {
    ......

    /**
     * Return the approximate per-application memory class of the current
     * device.  This gives you an idea of how hard a memory limit you should
     * impose on your application to let the overall system work best.  The
     * returned value is in megabytes; the baseline Android memory class is
     * 16 (which happens to be the Java heap limit of those devices); some
     * device with more memory may return 24 or even higher numbers.
     */
    public int getMemoryClass() {
        return staticGetMemoryClass();
    }

    /** @hide */
    static public int staticGetMemoryClass() {
        // Really brain dead right now -- just take this from the configured
        // vm heap size, and assume it is in megabytes and thus ends with "m".
        String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");
        return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
    }

    ......
}

Dalvik虛擬機在啓動的時候,就是通過讀取系統屬性dalvik.vm.heapsize的值來獲得Java Object Heap的最大值的,而ActivityManager類的成員函數getMemoryClass最終也通過讀取這個系統屬性的值來獲得Java Object Heap的最大值。

這個Java Object Heap的最大值也就是我們平時所說的Android應用程序進程能夠使用的最大內存。這裏必須要注意的是,Android應用程序進程能夠使用的最大內存指的是能夠用來分配Java Object的堆。

在Android3.0以及更高的版本中,我們還可以在AndroidManifest.xml的application標籤中增加一個值等於“true”的android:largeHeap屬性來通知Dalvik虛擬機應用程序需要使用較大的Java Object Heap。事實上這個屬性受限於手機內存,同時也會影響系統體驗(畢竟系統總共可用的內存是固定的,一個應用程序用得多了,就意味意其它應用程序用得少了)。

Bitmap Memory

Bitmap Memory也稱爲External Memory,它是用來處理圖像的,這部分內存受Java Object Heap的大小限制的

  • 在Android3.0之前,Bitmap Memory是在Native Heap中分配的,但是這部分內存同樣計入Java Object Heap中,也就是說,Bitmap佔用的內存和Java Object佔用的內存加起來不能超過Java Object Heap的最大值。這就是爲什麼我們在調用BitmapFactory相關的接口來處理大圖像時,會拋出一個OutOfMemoryError異常的原因。
  • 在Android3.0以及更高的版本中,Bitmap Memory就直接是在Java Object Heap中分配了,這樣就可以直接接受GC的管理。

Native Heap

Native Heap就是在Native Code中使用malloc等分配出來的內存,這部分內存是不受Java Object Heap的大小限制的,也就是它可以自由使用,當然它是會受到系統的限制。但是有一點需要注意的是,不要因爲Native Heap可以自由使用就濫用,因爲濫用Native Heap會導致系統可用內存急劇減少,從而引發系統採取激進的措施來Kill掉某些進程,用來補充可用內存,這樣會影響系統體驗。

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