davlik虚拟机内存管理之一——内存分配

dalvik 虚拟机是 Google Android 平台上的 Java 虚拟机的实现,内存管理是 dalvik 虚拟机中的一个重要组件。

从概念上来说,内存管理的核心就是两个部分:分配内存和回收内存。 Java 语言使用 new 操作符来分配内存,但是与 C/C++ 等语言不同的是, Java 语言并没有提供任何操作来释放内存,而是通过一种叫做垃圾收集的机制来回收内存。对于内存管理的实现,我们通过三个方面来加以分析:内存分配,内存回收和内存管理调试。本文就是这一系列文章的第一篇,分析 dalvik 虚拟机是如何分配内存的。

1.  对象布局

内存管理的主要操作之一是为
Java 对象分配内存, Java 对象在虚拟机中的内存布局如下:

 

所有的对象都有一个相同的头部 clazz lock
1 clazz:clazz 指向该对象的类对象,类对象用来描述该对象所属的类,这样可以很容易的从一个对象获取该对象所属的类的具体信息。
2 lock: 是一个无符号整数,用以实现对象的同步。
3 data: 存放对象数据,根据对象的不同数据区的大小是不同的。

2. 

堆是
dalvik 虚拟机从操作系统分配的一块连续的虚拟内存。 heapBase 是堆的起始地址, heapLimit 是堆的最大地址,堆大小的最大值可以通过 -Xmx 选项或 dalvik.vm.heapsize 指定。在原生系统中,一般 dalvik.vm.heapsize 值是 32M ,在 MIUI 中我们将其设为 64M
 

3.  堆内存位图

在虚拟机中维护了两个对应于堆内存的位图,称为 liveBits markBits

在对象布局中,我们看到对象最小占用 8 个字节。在为对象分配内存时要求必须 8 字节对齐。这也就是说,对象的大小会调整为 8 字节的倍数。比如说一个对象的实际大小是 13 字节,但是在分配内存的时候分配 16 字节。因此所有对象的起始地址一定是 8 字节的倍数。堆内存位图就是用来描述堆内存的,每一个 bit 描述 8 个字节,因此堆内存位图的大小是对的 64 分之一。对于 MIUI 的实现来说,这两个位图各占 1M

liveBits 的作用是用来跟踪堆中以分配的内存,每分配一个对象时,对象的内存起始地址对应于位图中的位被设为 1 。在下一篇垃圾收集中我们会进一步的分析 liveBits markBits 这两个位图的作用。

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 虚拟机的垃圾收集。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值