您好,欢迎访问三七文档
Dalvik虚拟机罗升阳://blog.csdn.net/luoshengyangAboutMe•《老罗的Android之旅》博客作者•《Android系统源代码情景分析》书籍作者•博客:•微博:•Dalvik虚拟机概述•Dalvik虚拟机的启动过程•Dalvik虚拟机的运行过程•JNI函数的注册过程•Dalvik虚拟机进程•Dalvik虚拟机线程Dalvik虚拟机概述•Dalvik虚拟机由DanBornstein开发,名字来源于他的祖先曾经居住过的位于冰岛的同名小渔村•Dalvik虚拟机起源于ApacheHarmony项目,后者是由Apache软件基金会主导的,目标是实现一个独立的、兼容JDK5的虚拟机,并根据ApacheLicensev2发布Dalvik虚拟机概述•Dalvik虚拟机与Java虚拟机的区别JavaVirtualMachineDalvikVirtualMachineInstructionSetJavaBytecode(StackBased)DalvikBytecode(RegisterBased)FileFormat.classfile(onefile,oneclass).dexfile(onefile,manyclasses)Dalvik虚拟机概述•基于堆栈的Java指令(1个字节)和基于寄存器的Dalvik指令(2、4或者6个字节)各有优劣•一般而言,执行同样的功能,Java虚拟机需要更多的指令(主要是load和store指令),而Dalvik虚拟机需要更多的指令空间•需要更多指令意味着要多占用CPU时间,而需要更多指令空间意味着指令缓冲(i-cache)更易失效Dalvik虚拟机概述•Dalvik虚拟机使用dex(DalvikExecutable)格式的类文件,而Java虚拟机使用class格式的类文件•一个dex文件可以包含若干个类,而一个class文件只包括一个类•由于一个dex文件可以包含若干个类,因此它可以将各个类中重复的字符串只保存一次,从而节省了空间,适合在内存有限的移动设备使用•一般来说,包含有相同类的未压缩dex文件稍小于一个已经压缩的jar文件Dalvik虚拟机概述•Dex文件的生成Dalvik虚拟机概述•Dex文件的优化–将invoke-virtual指令中的methodindex转换为vtableindex–加快虚函数调用速度–将get/put指令中的fieldindex转换为byteoffset–加快实例成员变量访问速度–将boolean/byte/char/short变种的get/put指令统一转换为32位的get/put指令–减小VM解释器的大小,从而更有效地利用CPU的i-cache–将高频调用的函数,例如String.length,转换为inline函数–消除函数调用开销–移除空函数,例如Object.init--消除空函数调用–将可以预先计算的数据进行预处理,例如预先生成VM根据classname查询class的hashtable–节省Dex文件加载时间以及内存占用空间Dalvik虚拟机概述•将invoke-virtual指令中的methodindex转换为vtableindex•将get/put指令中的fieldindex转换为byteoffsetinvoke-virtual{v1,v2},method@BBBBinvoke-virtual-quick{v1,v2},vtable#0xhhiget-objectv0,v2,field@BBBBiget-object-quickv0,v2,[obj+0x100]Dalvik虚拟机概述•Dex文件的优化时机–VM在运行时即时优化,例如使用DexClassLoader动态加载dex文件时。这时候需要指定一个当前进程有写权限的用来保存odex的目录。–APP安装时由具有root权限的installd优化。这时候优化产生的odex文件保存在特权目录/data/dalvik-cache中。–编译时优化。这时候编译出来的jar/apk里面的classes.dex被提取并且优化为classes.odex保存在原jar/apk所在目录,打包在systemimage中。Dalvik虚拟机概述•内存管理–JavaObjectHeap•大小受限,16M/24M/32M/48M/…–BitmapMemory(ExternalMemroy):•大小计入JavaObjectHeap–NativeHeap•大小不受限Dalvik虚拟机概述•JavaObjectHeap–用来分配Java对象。Dalvik虚拟机在启动的时候,可以通过-Xms和-Xmx选项来指定JavaObjectHeap的最小值和最大值。–JavaObjectHeap的最小和最大默认值为2M和16M。但是厂商会根据手机的配置情况进行调整,例如,G1、Droid、NexusOne和Xoom的JavaObjectHeap的最大值分别为16M、24M、32M和48M。–通过ActivityManager.getMemoryClass可以获得Dalvik虚拟机的JavaObjectHeap的最大值。Dalvik虚拟机概述•BitmapMemory–用来处理图像。在HoneyComb之前,BitmapMemory是在NativeHeap中分配的,但是这部分内存同样计入JavaObjectHeap中。这就是为什么我们在调用BitmapFactory相关的接口来处理大图像时,会抛出一个OutOfMemoryError异常的原因:java.lang.OutOfMemoryError:bitmapsizeexceedsVMbudget–在HoneyComb以及更高的版本中,BitmapMemory就直接是在JavaObjectHeap中分配了,这样就可以直接接受GC的管理。Dalvik虚拟机概述•NativeHeap–在NativeCode中使用malloc等分配出来的内存,这部分内存不受JavaObjectHeap的大小限制。–注意,不要因为NativeHeap可以自由使用就滥用,因为滥用NativeHeap会导致系统可用内存急剧减少,从而引发系统采取激进的措施来Kill掉某些进程,用来补充可用内存,这样会影响系统体验。Dalvik虚拟机概述•垃圾收集(GC)–Step1:Mark,使用RootSet标记对象引用–Step2:Sweep,回收没有被引用的对象•GingerBread之前–Stop-the-word,也就是垃圾收集线程在执行的时候,其它的线程都停止–Fullheapcollection,也就是一次收集完全部的垃圾–一次垃圾收集造成的程序中止时间通常都大于100ms•GingerBread之后–Cocurrent,也就是大多数情况下,垃圾收集线程与其它线程是并发执行的–Partialcollection,也就是一次可能只收集一部分垃圾–一次垃圾收集造成的程序中止时间通常都小于5msDalvik虚拟机概述•Dalvik虚拟机执行完成一次垃圾收集之后,我们通常可以看到类似以下的日志输出:•GC_CONCURRENT表示并行GC,2049K表示总共回收的内存,3571K/9991K表示JavaObjectHeap统计,即在9991K的JavaObjectHeap中,有3571K是正在使用的,4703K/5261K表示ExternalMemory统计,即在5261K的ExternalMemory中,有4703K是正在使用的,2ms+2ms表示垃圾收集造成的程序中止时间。D/dalvikvm(9050):GC_CONCURRENTfreed2049K,65%free3571K/9991K,external4703K/5261K,paused2ms+2msDalvik虚拟机概述•即时编译(JIT)–从2.2开始支持JIT,并且是可选的,编译时通过WITH_JIT宏进行控制–基于执行路径(ExecutingPath)对热门的代码片断进行优化(TraceJIT),传统的Java虚拟机以Method为单位进行优化(MethodJIT)–可以利用运行时信息进行激进优化,获得比静态编译语言更高的性能,如LazyUnlocking机制,可以参考《OracleJRockit:TheDefinitiveGuide》一书–实现原理:虚拟机概述•支持JDWP(JavaDebugWireProtocol)协议–每一个Dalvik虚拟机进程都都提供有一个端口来供调试器连接–DDMS提供有一个转发端口8870,通过它可以同时调试多个Dalvik虚拟机进程Dalvik虚拟机的启动过程•Dalvik虚拟机由Zygote进程启动,然后再复制到SystemServer进程和应用程序进程Dalvik虚拟机的启动过程•startVM的过程中会创建一个JavaVMExt,并且该JavaVMExt关联有一个JNIInvokeInterface,NativeCode通过它来访问Dalvik虚拟机Dalvik虚拟机的启动过程•startVM的过程中还会为当前线程关联有一个JNIEnvExt,并且该JNIEnvExt关联有一个JNINativeInterface,NativeCode通过它来调用Java函数或者访问Java对象Dalvik虚拟机的启动过程•Dalvik虚拟机在Zygote进程启动的过程中,还会进一步预加载Java和Android核心类库以及系统资源Dalvik虚拟机的启动过程•Dalvik虚拟机从Zygote进程复制到SystemServer进程之后,它们就通过COW(CopyOnWrite)机制共享同一个Dalvik虚拟机实例以及预加载类库和资源Dalvik虚拟机的启动过程•Dalvik虚拟机从Zygote进程复制到应用程序进程之后,它们同样会通过COW(CopyOnWrite)机制共享同一个Dalvik虚拟机实例以及预加载类库和资源Dalvik虚拟机的运行过程•Dalvik虚拟机在Zygote进程中启动之后,就会以ZygoteInit.main为入口点开始运行•Dalvik虚拟机从Zygote进程复制到SystemServer进程之后,就会以SystemServer.main为入口点开始运行•Dalvik虚拟机Zygote进程复制到应用程序进程之后,就会以ActivityThread.main为入口点开始运行•上述入口点都是通过调用JNINativeInterface接口的成员函数CallStaticVoidMethod来进入的Dalvik虚拟机的运行过程•JNINativeInterface-CallStaticVoidMethod对应的实现为CallStaticVoidMethodVDalvik虚拟机的运行过程•CallStaticVoidMethodV调用dvmCallMethodVDalvik虚拟机的运行过程•在Dalvik虚拟机中,无论是Java函数,还是Native函数,都是通过Method结构体来描述的Dalvik虚拟机的运行过程•在Dalivk虚拟机中,通过dvmIsNativeMethod判断一个函数是Java函数还是Native函数Dalvik虚拟机的运行过程•Native函数直接由CPU执行,Java函数由Dalvik虚拟机解释执行,即通过dvmInterpret函数执行Dalvik虚拟机的运行过程•Dalvik虚拟机标准解释器:dvmInterpretStdDalvik虚拟机的运行过程•Invoke-direct指令由函
本文标题:Dalvik虚拟机
链接地址:https://www.777doc.com/doc-2909417 .html