davlik虛擬機內存管理之一——內存分配

dalvik虛擬機是GoogleAndroid平臺上的Java虛擬機的實現,內存管理是dalvik虛擬機中的一個重要組件。

從概念上來說,內存管理的核心就是兩個部分:分配內存和回收內存。Java語言使用new操作符來分配內存,但是與C/C++等語言不同的是,Java語言並沒有提供任何操作來釋放內存,而是通過一種叫做垃圾收集的機制來回收內存。對於內存管理的實現,我們通過三個方面來加以分析:內存分配,內存回收和內存管理調試。本文就是這一系列文章的第一篇,分析dalvik虛擬機是如何分配內存的。

1. 對象佈局

內存管理的主要操作之一是爲
Java對象分配內存,Java對象在虛擬機中的內存佈局如下:

123021aeysrv0bwwv3wvu7.jpg

所有的對象都有一個相同的頭部clazzlock
1clazz:clazz指向該對象的類對象,類對象用來描述該對象所屬的類,這樣可以很容易的從一個對象獲取該對象所屬的類的具體信息。
2lock:是一個無符號整數,用以實現對象的同步。
3data:存放對象數據,根據對象的不同數據區的大小是不同的。

2.

堆是
dalvik虛擬機從操作系統分配的一塊連續的虛擬內存。heapBase是堆的起始地址,heapLimit是堆的最大地址,堆大小的最大值可以通過-Xmx選項或dalvik.vm.heapsize指定。在原生系統中,一般dalvik.vm.heapsize值是32M,在MIUI中我們將其設爲64M
123021a7xckd2kkktkxj74.jpg

3. 堆內存位圖

在虛擬機中維護了兩個對應於堆內存的位圖,稱爲liveBitsmarkBits

在對象佈局中,我們看到對象最小佔用8個字節。在爲對象分配內存時要求必須8字節對齊。這也就是說,對象的大小會調整爲8字節的倍數。比如說一個對象的實際大小是13字節,但是在分配內存的時候分配16字節。因此所有對象的起始地址一定是8字節的倍數。堆內存位圖就是用來描述堆內存的,每一個bit描述8個字節,因此堆內存位圖的大小是對的64分之一。對於MIUI的實現來說,這兩個位圖各佔1M

liveBits的作用是用來跟蹤堆中以分配的內存,每分配一個對象時,對象的內存起始地址對應於位圖中的位被設爲1。在下一篇垃圾收集中我們會進一步的分析liveBitsmarkBits這兩個位圖的作用。

4. 堆的內存管理

dalvik虛擬機實現中,是通過底層的bionicC庫的malloc/free操作來分配/釋放內存的。bionicC庫的malloc/free操作是基於DougLea的實現(dlmalloc),這是一個被廣泛使用,久經考驗的C內存管理庫,本文不展開dlmalloc的具體實現,有興趣的讀者請參考http://g.oswego.edu/dl/html/malloc.html

5. dvmAllocObject

dalvik虛擬機中,new操作符最終對應dvmAllocObject這個C函數。下面通過僞碼的形式列出dvmAllocObject的實現。
Object*dvmAllocObject(ClassObject *clazz, int flags) {
       n = get object size form class object clazz
       first try: allocate n bytes from heap
       if first try failed {
               run garbage collector without collecting soft references
               second try: allocate n bytes from heap
       }
       if second try failed {
               third try: grow the heap and allocate n bytes from heap
               (註釋:堆是虛擬內存,一開始並未分配所有的物理內存,只要還沒有達到虛擬內存的最大值,可以通過獲取更多物理內存的方式來擴展堆)
       }
       if third try failed {
               run garbage collector with collecting soft references
               fourth try: grow the hap and allocate n bytes from heap
       }
       if fourth try failed, return null pointer, dalvik vm will abort
}

可以看出,爲了分配內存,虛擬機盡了最大的努力,做了四次嘗試。其中進行了兩次垃圾收集,第一次不收集SoftReference,第二次收集SoftReference。從中我們也可以看出垃圾收集的時機,實質上在dalvik虛擬機實現中有3個時機可以觸發垃圾收集的運行:
1)程序員顯式的調用System.gc()
2)內存分配失敗時
3)如果分配的對象大小超過384KB,運行併發標記(concurrent mark),在下一篇文章中會介紹什麼是併發標記

6.小結
dalvik虛擬機中,內存分配操作的流程相對比較簡單直觀,從一個堆中分配可用內存,分配失敗時觸發垃圾收集,接下來的文章中我們仔細分析dalvik虛擬機的垃圾收集。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章