JVM和Android虚拟机知识点总结

2023-11-19

1. JVM,Dalvik,Art虚拟机的区别

1.1 JVM和Dalvik的区别

JVM可以将平台无关的字节码文件(.class文件)根据不同的平台翻译成不同的机器码,来实现跨平台。

一般情况下,JVM执行的都是.class文件,我们的java文件编译后都会变为class文件,

而Dalvik作为Android平台独有的虚拟机,他执行的不是.class文件,而是.dex文件。.dex文件用dex工具将项目中多个.class文件转为一个.dex文件。

1.2 Dalvik和Art的区别

Dalvik使用JIT(just in time)编译: 应用程序每次在运行时,会将app中的dex文件实时的转成机器码在运行。dex文件占得内存小,但是由于要实时转换成机器码,所以运行所需要的时间更多。经典的以时间换空间

ART使用AOT(ahead of time)编译:应用在安装期间,他会提前将dex字节码翻译成机器码并且存储在设备上。然后在运行时,只需要直接运行机器码即可。但是由于要将机器码安装到设备上,所以所需要的设备容量就会更多。经典的以空间换时间。

在Android4.4之前,Android应用程序安装的速度很快,但是启动速度却稍慢。而在4.4之后,应用程序的体积不仅变大了,并且安装所需要的时间也变得更多。这就是因为用了不同的编译方式。

2. Class文件和dex文件的区别

Dex文件相当于将多个class文件合并在一起之后再进行压缩,所以一个dex文件是对应着多个class文件。

  1. dex文件减少整体的文件尺寸 dex更像是一种压缩文件,一次可以表示更多的class。class像是一种单个文件
  2. Android虚拟机加载类时 只对dex需要一次IO可以加载很多新类,而class需要加载多次IO,Android虚拟机提高查找速度
  3. dex指令更加密集,class指令比较多 。
  4. dex 寄存器设计方便寻址,class java栈需要更多次load与store指令。
  5. dex适合于移动设备,性能不太高的要求。class适合PC大内存,单指令小的情况下可以快速执行。

3. 基于寄存器的Android虚拟机和基于栈的JVM

3.1 栈和栈帧

先回顾一下栈和栈帧的概念,在JVM中,Java方法每当被执行的时候,就会将这个方法加入栈帧。每个方法的执行到结束就是入栈到出栈的过程。

而栈帧就存放在Java栈中。每一个栈帧都包括了局部变量表,操作数栈,动态连接,方法返回地址和一些额外的附加信息。在编译代码的时候,栈帧中需要多大的局部变量表,多深的操作数栈都已经完全确定了,并且写入到了方法表的Code属性中,因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体虚拟机的实现。

在这里插入图片描述

3.2 JVM,基于栈

首先,这里的基于栈,不是指java栈,而是指栈帧内部中的操作数栈。虚拟机在真正进行运算(加减乘除赋值等)时,都会直接通过操作数栈来进行,而不会直接去操作内存中的数据(虚拟机中的内存,因为在物理意义上,java栈也在内存中)。

执行时都是从操作数栈上取值,不需要指定目标操作数。
比如加法操作 a = b + c。那么首先会将b和c的数据放到操作数栈上,然后执行加法的同时,将操作数栈的栈顶pop,最后将结果存放在操作数栈顶,然后存放在变量C上。

a = b+c 的字节码
I1: LOAD C // 将c加入操作数栈
I2: LOAD B // 将b加入操作数栈
I3: ADD // 将栈顶的两个元素出栈,同时将这两个元素的和入栈
I4: STORE A // 将栈顶元素存放到a

在这里插入图片描述
在这里插入图片描述

3.3 Android虚拟机,基于寄存器

先介绍一下寄存器(不过虚拟机中的寄存器也是虚拟的寄存器):
寄存器就是你的口袋。身上只有那么几个,只装最常用或者马上要用的东西。
内存就是你的背包。有时候拿点什么放到口袋里,有时候从口袋里拿出点东西放在背包里。
辅存就是你家里的抽屉。可以放很多东西,但存取不方便。

基于寄存器的虚拟机,栈帧中就没有操作数栈和局部变量表了。取而代之的是内部有一个虚拟寄存器(其实就是在内存中开辟一块连续的空间),用于存放方法中会用到的变量(包括方法的参数列表,返回类型和方法中创建的变量)。

还是刚刚的a = b+c,这次再基于寄存器的虚拟机中,字节码是这样的:

add-int v0, v1, v2
注:在寄存器中,变量名都以v+数字或者p+数字命名,无关我们在java文件时的取名

在这里插入图片描述

4. 基于栈和基于寄存器虚拟机的区别

4.1 栈式

基于栈的虚拟机,其最大的特点就是即使是最简单的运算,也要通过操作数栈来进行。

这样做的好处就是:虚拟机可以直接无视底层的物理架构。物理硬件中的寄存器只要能处理好操作数栈的操作即可,至于运算的具体各种操作仅由虚拟机本身来进行负责。这样一来虚拟机的移植性就很强,移植到其他的系统时会比较容易。

缺点也很明显:指令多,而且数据的传输也很慢,因为即使是一个最简单的加法操作,也要进行多次的取数和存数的指令,在内存中运行的指令越多,运行效率就越慢。

4.2 寄存器式

基于寄存器的虚拟机,由于指令需要指定源地址和目标地址,所以单个指令所占用的空间就更多。

好处就是:直接经由CPU运算,运算的速度就会更快,因为访问内存的次数更少。

缺点就是:每个指令所占的空间更多。而且移植性也没有基于栈的虚拟机强。

4.3 对比

指令条数 栈式 > 寄存器式
代码尺寸 栈式 < 寄存器式
移植性 栈式优于寄存器式
指令优化 栈式更不易优化
解释器执行速度 栈式解释器速度稍慢
代码生成难度 栈式简单
数据移动次数 栈式移动次数多

4.4 Android平台为什么要设计基于寄存器的虚拟机

在了解了两种虚拟机之后,最后就要分析一下这个问题。

移动平台最大的特点就是:在性能方面,远远比不上传统平台。这里的性能包括指令执行速度,IO速度等。

拿2021年刚出骁龙888举例,在忽视各种元素的情况下,骁龙888的满载功耗不过10w,而笔记本平台近几年常用的CPU功耗都在25W以上。虽然移动平台的特点就是重视能耗比,但是也不会高到说和传统平台持平(更别说Android刚出的那几年了)。且移动平台不能说是CPU而是SOC,他的核心内还集成了很多其他功能。

在性能较低的情况下,想要保证用户日常的使用体验,让用户打开app的时候不会感受到太多的卡顿等问题,那么只能设计基于寄存器的虚拟机,它的运行速度更快,效率更高。

使用这种空间换时间的方式,虽然会增加应用软件所占用的体积,但是日常所用的软件占用空间就算相比基于栈的虚拟机高,也不会说高到不可接受的地步。

参考材料

https://blog.csdn.net/xtayfjpk/article/details/41924283?utm_source=tuicool&utm_medium=referral
深入理解Java虚拟机笔记—运行时栈帧结构_xtayfjpk的专栏-CSDN博客_运行时栈帧概念结构
https://www.cnblogs.com/hainange/p/6333995.html
基于寄存器与基于栈的虚拟机 - 海南一哥 - 博客园

码牛学院VIP课程 2020.4.27

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JVM和Android虚拟机知识点总结 的相关文章

随机推荐