ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JVM vs. DVM vs. ART

JVM vs. DVM vs. ART JVM vs. DVM 的核心区别基于的架构不同JVM基于栈需要去栈中读写数据所需的指令更多导致速度变慢对于性能有限的移动设备不是很适合DVM 基于寄存器 指令紧凑更简洁可以减少指令分派、取指和解释执行的次数降低CUP开销因此更适合移动设备有限的CPU和内存环境JVM 是栈式虚拟机运算依赖频繁压栈出栈指令数量多解释执行时 CPU 取指开销大DVM 采用虚拟寄存器架构单条指令可以完成复杂运算减少指令执行次数降低 CPU 消耗更适配早期移动设备有限的算力。解释器执行每条字节码时都需要经过取指、解码、分派和执行。取指是读取下一条字节码分派是根据操作码跳转到对应的处理逻辑解释执行则是由解释器完成该指令表示的操作。寄存器型字节码通常用更少的指令完成相同任务因此可以减少解释器循环和指令分派次数这在以解释执行为主的早期移动设备上有一定性能优势。执行的字节码不同JVM 会从.class文件 或 打包的.jar文件 中获取相应的字节码。每个.class文件里面包含了该类的常量池、类信息、属性等。当JVM加载.jar文件的时候会加载里面的所有的.class文件JVM 的这种方式很慢对内存有限的移动设备不适合。DVM 会从.dex文件 读取指令和数据。在.apk文件中只包含了一个.dex文件这个.dex文件会将所有的.class里面包含的信息全部整合在一起并且 dex 工具会去除很多.class文件的冗余信息将 .class 文件整合到 .dex 文件中 降低内存开销、减少了 I/O 操作加快了类的查找速度。DVM 早期没有使用 JIT 编译器JVM 使用了 JIT 编译器Just In Time Compiler即时编译器而 DVM 早期没有使用 JIT 编译器。早期的 DVM 每次执行代码都需要通过解释器将 dex 代码编译成机器码然后交给系统处理效率不是很高。为了解决该问题后期DVM 使用了 JIT 编译器它会对多次运行的代码热点代码进行编译生成相当精简的本地机器码Native Code这样在下次执行到相同逻辑的时候直接使用编译之后的本地机器码而不是每次都需要编译。Dalvik 与 ART 的核心区别编译方式不同核心Dalvik采用JIT即时编译每次运行应用时字节码实时编译为机器码程序运行效率低。本质上还是解释执行边解释边执行ART默认采用AOT预编译安装时一次性将字节码编译为本地机器码运行流畅、省电但安装耗时、占用空间大。Android 7.0 混合模式ART 加入 JIT 作为补充安装时不将字节码全编译为机器码运行时识别编译热点代码为机器码平衡安装速度、空间和运行性能。CPU 架构支持Dalvik 仅支持32 位CPUART 支持64 位且兼容 32 位是 Dalvik 被淘汰的重要原因。32 位寻址上限 4GB限制 App 使用大内存64 位放开逻辑限制程序才有能力去使用大容量物理内存。垃圾回收GC优化ART 对 GC 进行了改进堆内存划分更精细回收效率更高减少了应用卡顿。体现堆划分更精细Dalvik整个堆一大块。回收经常扫描全部对象耗时久。 按来源划分了两个区域 系统启动类、静态对象、全局只读共享在一个区域Zygote space APP 的所有业务对象在 一个区域Active 堆。 然后 整个区域 同时做 标记清除。一旦堆变大GC 扫描耗时久STW 停顿长碎片严重ART 把 Java 堆分成不同区域新生代、老年代、大对象区。新生代存放短命临时对象循环、局部临时对象回收快、停顿很短老年代长期存活对象页面数据、全局变量回收频率低大对象单独管理不用扫描一堆小对象小垃圾快速清理不用每次都扫描整个内存。减少长时间 STW核心优化Dalvik标记阶段全部暂停。 ART 改成大部分标记工作和 App 线程并发执行一边跑 App一边标记垃圾 只有很短的小段时间需要暂停主线程GC 停顿时间大幅缩短。多线程并行回收回收的时候启用多个 CPU 线程一起清理垃圾加快整体 GC 速度。回收策略优化新生代使用复制回收速度快老年代采用并发标记清除更智能的触发时机尽量不在用户滑动、动画这种关键界面操作时执行重 GC。JIT 是什么JIT 出现之前或尚未触发时JVM 通过解释器逐条读取和分派字节码执行解释器内部已有的本地处理逻辑当方法或循环成为热点后JIT 会把整段字节码编译成本地机器码后续直接执行机器码不再逐条解释。每条字节码都包含一个opcode有些指令后面还带操作数。根据 操作码 选择对应处理逻辑的过程就是指令分派dispatch。没有 JIT 字节码 → 解释器逐条分派 → 本地 handler → CPU 有 JIT 前期 字节码 → 解释器 热点后 字节码 → JIT 编译 → 本地机器码 → CPU 直接执行“解释执行 JIT 编译”的混合模式Java 源代码先通过javac编译成.class字节码。程序刚启动时解释器逐条解释字节码并执行因此启动较快。JVM 会统计代码的执行频率。当某个方法或循环成为热点代码后JIT 编译器会把它编译成本地机器码。后续再次执行热点代码时直接运行机器码从而提高性能。
返回列表