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

链接:http://www.miui.com/forum-viewthread-tid-74715-extra-%26page%3D1-page-1.html


从概念上来说,内存管理的核心就是两个部分:分配内存和回收内存。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 虚拟机的垃圾收集。

更多相关文章

  1. Android中的postDelayed的用法
  2. Android中的UID和AppId
  3. 【Xcode应用】iOS性能分析
  4. android parcelable 以及android studio插件
  5. Android消息处理机制①
  6. 【转】Android内存泄漏简介
  7. 让class只有一个实例的例子
  8. android 在Google地图上添加标记
  9. Android之使用私有存储

随机推荐

  1. Android 重新编译frameworks/base/core/r
  2. Android okhttp3 创建Socket的底层实现追
  3. Android Support Design Library使用详解
  4. 开发笔记( android背景透明度怎么设置)(20
  5. Android中自定义对话框(Dialog)
  6. Android和js的混合开发
  7. Android的DHCP功能
  8. Android Studio使用Lint进行代码检查
  9. Android 一般动画Animation和属性动画Ani
  10. 初学Android做计时器和代码