davlik虚拟机内存管理之一——内存分配
16lz
2021-01-26
dalvik虚拟机是Google在Android平台上的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 虚拟机的垃圾收集。
链接:http://www.miui.com/forum-viewthread-tid-74715-extra-%26page%3D1-page-1.html
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 虚拟机的垃圾收集。
更多相关文章
- Android中的postDelayed的用法
- Android中的UID和AppId
- 【Xcode应用】iOS性能分析
- android parcelable 以及android studio插件
- Android消息处理机制①
- 【转】Android内存泄漏简介
- 让class只有一个实例的例子
- android 在Google地图上添加标记
- Android之使用私有存储