什么是 Dalvik?
要了解 Android 应用的内存管理机制,就要了解承载着 Android 应用的虚拟机 Dalvik,虽然 Android 现在是使用的 ART 来承载应用的执行,但是 ART 也是基于 Dalvik 优化而来的。
Dalvik 是 Dalvik Virtual Machine(Dalvik 虚拟机)的简称,是 Android 平台的核心组成部分之一,Dalvik 与 JVM 的区别有如下几个。
Dalvik 与 JVM 的区别
-
架构
JVM 是基于栈的,也就是需要在栈中读取数据,所需的指令会更多,这样会导致速度慢,不适合性能优先的移动设备。
Dalvik 是基于寄存器的,指令更紧凑和简洁。
由于显式指定了操作数,所以基于寄存器的指令会比基于栈的指令要大,但是由于指令数的减少,总的代码数不会增加多少。
-
执行代码不同
在 Java SE 程序中,Java 类会被编译成一个或多个 .class 文件,然后打包成 jar 文件,JVM 会通过对应的 .class 文件和 jar 文件获取对应的字节码。
而 Dalvik 会用 dx 工具将所有的 .class 文件转换为一个 .dex 文件,然后会从该 .dex 文件读取指令和数据。
-
Zygote
Dalvik 由 Zygote 孵化器创建,Zygote 本身也是一个 Dalvik VM 进程,当系统需要创建一个进程时,Zygote 就会进行 fork,快速创建和初始化一个 DVM 实例。
对于一些只读的系统库,所有的 Dalvik 实例都能和 Zygote 共享一块内存区域,这样能节省内存开销。
-
有限内存运行多进程
在 Androd 中,每一个应用都运行在一个 Dalvik VM 实例中,每一个 Dalvik VM 都运行在一个独立的进程空间,这种机制使得 Dalvik 运行在有限的内存中同时运行多个进程。
-
共享机制
Dalvik 拥有预加载—共享机制,不同应用之间在运行时可以共享相同的类,拥有更高的效率。
而 JVM 不存在这种共享机制,不同的程序,打包后的程序都是彼此独立的,即使包中使用了同样的类,运行时也是单独加载和运行的,无法进行共享。
-
不是 JVM
Dalvik 不是 Java 虚拟机,它并不是按照 Java 虚拟机规范实现的,两者之间并不兼容。
Dalvik 堆大小
每一个手机厂商都可以设定设备中每一个进程能够使用的堆大小,设置进程堆大小的值有下面三个。
-
dalvik.vm.heapstartsize
堆分配的初始值大小,这个值越小,系统内存消耗越慢,但是当应用扩展这个堆,导致 GC 和堆调整时,应用会变慢。
这个值越大,应用越流畅,但是可运行的应用也会相对减少。
-
dalvik.vm.heapgrowthlimit
如果在清单文件中声明 largeHeap 为 true,则 App 使用的内存到 heapsize 才会 OOM,否则达到 heapgrowthlimit 就会 OOM。
-
dalvik.vm.heapsize
进程可用的堆内存最大值,一旦应用申请的内存超过这个值,就会 OOM。
假如我们想看其中的一个值,我们可以通过命令查看,比如下面这条命令。
adb shell getprop dalvik.vm.heapsize
复制代码
什么是 ART?
ART 的全称是 Android Runtime,是从 Android 4.4 开始新增的应用运行时环境,用于替代 Dalvik 虚拟机。
Dalvik VM 和 ART 都可以支持已转换为 .dex(Dalvik Executable)格式的 Java 应用程序的运行。
ART 与 Dalvik 的区别有下面几个。
-
预编译
Dalvik 中的应用每次运行时,字节码都需要通过即时编译器 JIT 转换为机器码,这会使得应用的运行效率降低。
在 ART 中,系统在安装应用时会进行一次预编译,将字节码预先编译成机器码并存储在本地,这样应用就不用在每次运行时执行编译了,运行效率也大大提高。
-
GC
在 Dalvik 采用的垃圾回收算法是标记-清除算法,启动垃圾回收机制会造成两次暂停(一次在遍历阶段,另一次在标记阶段)。
而在 ART 下,GC 速度比 Dalvik 要快,这是因为应用本身做了垃圾回收的一些工作,启动 GC 后,不再是两次暂停,而是一次暂停。
而且 ART 使用了一种新技术(packard pre-cleaning),在暂停前做了许多事情,减轻了暂停时的工作量。
-
64 位
Dalvik 是为 32 位 CPU 设计的,而 ART 支持 64 位并兼容 32 位 CPU,这也是 Dalvik 被淘汰的主要原因。