Dalvik虚拟机(DVM)是Google专门为Android平台开发的虚拟机。它运行在Android运行时库中。其名字来源于作者Bornstein的祖先居住过的名为Dalvik的小渔村。
DVM的设计没有遵循JVM规范来实现,这也是后来导致Google被Oracle起诉的原因。
JVM基于栈,DVM基于寄存器。
JVM:.java文件->.class文件->.jar文件
DVM:.java文件->.class文件->.dex文件->.apk文件
DVM通过dx工具将所有的class文件整合成一个dex文件,并去掉其中冗余的信息。
不同应用运行时可以共享相同的类,JVM不同的程序是独立的。
DVM运行时使用标记——清除算法进行GC。由两个Space和多个辅助数据结构组成。两个Space为Zygote Space(Zygote Heap)和Allocation Space(Active Heap)。
用来管理Zygote进程在启动过程中预加载和创建的各种对象。Zygote Space不会触发GC。Zygote进程和应用程序进程间共享Zygote Space。
在Zygote进程fork第一个子进程之前,会将Zygote Space分成两部分,原来被使用的部分仍未Zygote Space,而未使用的部分为Allocation Space。以后的对象都在Allocation Space上进行分配和释放。Allocation Space在每个进程中都独立拥有一份,且进程间不共享。
用于DVM Concurrent GC,当第一次进行垃圾标记后,记录垃圾信息。
有两个Heap Bitmap,一个用来记录上次GC存活的对象,另一个用来记录这次GC存活的对象。
在GC标记阶段使用,用来遍历存活的对象。
D/dalvikvm:
参数:
GC_Reason:引起GC的原因。
Amount_freed:本次GC释放内存的大小。
Heap_stats:堆的空闲内存百分比 (已用内存/堆的总内存)。
External_memory_stats:API小于等于级别10的内存分配 (已分配的内存/引起GC的阈值)。
Pause_time:暂停时间。并发暂停时间有两个:一个在垃圾收集开始,一个在垃圾收集完成。
i)GC_CONCURRENT:当堆开始填充时,并发GC可以释放内存。
ii)GC_FOR_MALLOC:当堆内存已满时,App尝试分配内存而引起的GC,系统必须停止App并回收内存。
iii)GC_HPROF_DUMP_HEAP:当用户请求创建HPROF文件来分析堆内存时出现的GC。
iv)GC_EXPLICIT:显式GC,例如调用System.gc();。
v)GC_EXTERNAL_ALLOC:仅适用于API级别小于等于10,且用于外部分配内存的GC。
Android4.4后用来替换Dalvik虚拟机。
JIT编译:Just In Time,DVM中的应用每次运行时,JIT编译器将字节码转换成机器码。
AOT编译:Ahead Of Time,ART中系统在安装应用程序时会事先将字节码编译成机器码并存储在本地。
ART采用多种垃圾收集方案,每个方案运行不同的垃圾收集器。对于不同的方案,ART的运行时堆划分不同。默认方案为CMS(并发标记清除)方案,使用sticky-CMS和partial-CMS。默认的ART运行时堆由4个Space和多个辅助数据结构组成。4个Space分别为Zygote Space、Allocation Space、Image Space、Large Object Space。
与DVM相同,进程间共享。
与DVM相同。
用来存放一些预加载类,进程间共享。
用来分配一些大对象,默认大小为12KB。
ART的Java堆还包含两个Mod Union Table,一个Card Table,两个Heap Bitmap,两个Object Map,以及三个Object Stack。
ART会为主动请求的垃圾收集事件或者认为GC速度慢时才会打印GC日志。GC速度慢是指GC暂停超过5ms或者GC持续时间超过100ms。
I/art:
参数:
GC_Reason:引起GC的原因。
GC_Name:垃圾收集器的名称。
Objects_freed:本次GC从非Large Object Space中回收的对象的数量。
Size_freed:本次GC从非Large Object Space中回收的字节数。
Large_objects_freed:本次GC从Large Object Space中回收的对象数量。
Large_object_size_freed:本次GC从Large Object Space中回收的字节数。
Heap_stats:堆的空闲内存百分比,即(已用内存/堆的总内存)。
Pause_time(s):暂停时间。ART只暂停一次,出现在GC结束。
i)Concurrent:并发GC,不会使App的线程暂停,该GC在后台线程运行,不会阻止内存分配。
ii)Alloc:当堆内存已满时,App尝试分配内存引起的GC,这个GC会发生在正在分配内存的线程中。
iii)Explicit:App显式的请求垃圾回收,例如调用System.gc()。
iv)NativeAlloc:Native内存分配时,触发的GC。
v)CollectorTransition:由堆转换引起的回收,运行时切换GC引起的。将所有对象从空闲列表空间复制到碰撞指针空间,反之亦然。仅出现在内存较小的设备上App将进程从可察觉的暂停状态更改为可察觉的非暂停状态。
vi)HomogeneousSpaceCompact:齐性空间压缩是指空闲列表到压缩的空闲列表空间,通常发生在App移动到可察觉的暂停进程状态。以此来减小内存使用并对堆内存进行碎片整理。
vii)DisableMovingGc:不是真正触发GC的原因。发生并发堆压缩时,由于使用了GetPrimitiveArrayCritical,收集会被阻塞。
viii)HeapTrim:不是触发GC的原因。收集会一直被阻塞,直到堆内存整理完毕。
i)Concurrent Mark Sweep(CMS):CMS收集器是一种以获取最短收集暂停时间为目标的收集器,采用标记-清除算法实现。它是完整的堆垃圾收集器,能释放除了Image Space外的所有空间。
ii)Concurrent Partial Mark Sweep:部分完整的堆垃圾收集器,能释放除了Image Space和Zygote Space外的所有空间。
iii)Concurrent Sticky Mark Sweep:粘性收集器,基于分代的垃圾收集思想,只能释放自上次GC以来分配的对象。它比一个完整的或部分完整的垃圾收集器扫描的更频繁,因为它更快且暂停时间更短。
iv)Marksweep + Semispace:非并发的GC,复制GC用于堆转换以及齐性空间的压缩。
判断若为Zygote进程,则调用AppRuntime对象的start函数启动Zygote进程,内部调用startVm函数启动Java虚拟机。
1.调用JniInvocation对象的Init函数,初始化虚拟机环境。
1)调用GetLibrary函数,获取系统的虚拟机类型,libart.so或libdvm.so。
2)调用dlopen函数加载libart.so或libdvm.so。
2.调用startVm函数,启动虚拟机。
3.调用startReg函数,为虚拟机注册JNI方法。