1.前言
首要希望觉得本片文章有用的童鞋们记得点赞!重视!收藏!,不要小气你们的称誉啦!
Android的虚拟机通过演变,从Android5.0前的Dalvik虚拟机在Android5.0后全面变成了ART虚拟机,这两个虚拟机都是根据寄存器的,而咱们的JVM是根据栈的。
那为什么安卓的虚拟机是根据寄存器,跟JVM根据栈有所不同呢?最大的原因必定是因为移动端的硬件环境进行了针对性相关优化,比方安卓里边字节码文件是.dex而不class,那正是谷歌对移动端进行了相关针对性的优化,那这个时分就要将JVM根据栈的模式与根据寄存器的模式进行一个比照,咱们才干了解为什么安卓虚拟机会根据寄存器。
2.栈与寄存器的差异
在介绍JVM之前,咱们先了解栈与寄存器的差异是什么?
先上结论!!!
所以为什么Android渠道根据寄存器的规划?
- 指令条数少,所以履行的功率更快!
- 数据移动次数少、临时成果存放次数少,所以更省内存和履行功率更快!
- 映射真实机器的寄存器,所以履行功率更快!
2.1.栈
栈的特点是:FILO(先进后出,Fist In Last Out)
栈的出入口只要一个,那就意味着先进的元素会在栈底,而后进的元素会在栈底,先进的元素不能直接出栈,需求栈顶的元素出栈后,才干出栈,所以栈是一个单向队列的数据结构,咱们先上图来描绘一下栈。
咱们能够看出,A元素是首要进入栈的,这个时分会被处于栈顶,随着B元素的进入,A元素被压入栈底,而B元素处于栈顶,最后C元素压入栈中,成为了栈顶,这个时分A、B元素出栈都意味着C元素必须要出栈。
Ok,栈的概念仍是比较简单明白的,接下来咱们看看寄存器的概念。
2.2.寄存器
寄存器相当于CPU里边的内存,它本身是有固定的内存地址的,这意味着数据在寄存器中的操作/IO是非常快速的。
寄存器的指令一般较长,在Android里边每个指令占2个字节,可是指令条数会大幅减少,而JVM虚拟站中指令占一个字符,可是指令条数会大幅增加,能快速履行。
那么简单介绍完栈与寄存器的概念之后,咱们就进入下一章,JVM是怎样通过虚拟栈来履行指定的?
3.JVM是怎样通过虚拟栈履行字节码文件的?
3.1 了解JVM运行时的数据区组成
首要咱们要了解JVM运行时的数据区,看一幅图:
咱们能够由上图看出,ClassLoader将.class文件加载至运行时数据区,运行时数据区其实便是字节码被加载到内存后在内存的一个状况,咱们能够看出有以下几部分。
- 堆
存放着实例的区域,而GC主要也是针对该区域。
- 办法区
存放着从字节码中加载出来的类信息。
- 线程独立区域
- 程序计数器 保存程序字节码履行的顺序
- 虚拟机栈 描绘java办法履行的内存模型
- 本地办法栈 本地办法栈则为Native 办法服务
简单了解了运行时数据区的结构后,接下来咱们将深化到JVM中的线程是怎样根据虚拟机栈来履行字节码的。
3.2 了解栈帧
咱们知道虚拟机栈是负责描绘java办法履行的内存模型,而且记载线程内办法的履行状况的,而栈中的元素,也会被称为栈帧,比方咱们现在履行一个main办法,main办法中再履行一个foo办法,那么虚拟机栈中就会存在两个栈帧,如图:
那如果此刻咱们的虚拟机栈中的foo办法含有相关逻辑,虚拟机栈又是怎样履行这些逻辑的呢?
首要,咱们的虚拟机栈是怎样履行以上字节码的呢?首要咱们了解一下栈帧的组成
咱们能够看出一个栈帧里边含有
- 局部变量表
局部变量表存放着办法中的局部变量+this实例
- 操作数栈
用于字节码履行时,暂存其中间状况的一个内存区域,每个操作数栈的容量是有限的,在编译期会揣度其容量巨细而且记载在字节码文件中,而JVM说的根据栈,其实便是根据该操作数栈。
- 办法出口
记载该办法的出口,需求回来什么,回来给谁。
- 程序计数器
记载着程序的履行顺序。
3.3 了解栈是怎样履行逻辑的
接下来咱们界说一个foo办法,而且编译成class文件,然后咱们解析一下虚拟机栈是怎样履行字节码程序的。
public void foo() {
int a = 1;
int b = 2;
int c = (a + b)*9;
}
然后咱们将其解析成字节码后是这样的
顺序 | 字节码 | 助记符 |
---|---|---|
0 | 0x04 | iconst_1 |
1 | 0x3b | istore_0 |
2 | 0x05 | iconst_2 |
3 | 0x3c | istore_1 |
4 | 0x1a | iload_0 |
5 | 0x1b | uload_1 |
6 | 0x60 | iadd |
7 | 0x10 0x09 | bipush9 |
9 | 0x67 | imul |
a | 0x3d | istore_2 |
b | 0xb1 | return |
那么栈帧中是怎样履行上面的字节码的?
咱们以图解的方式解析全进程,首要是一个栈帧的初始化状况,局部变量表与操作数栈的状况如下:
咱们能够看出局部变量表中初始化了a,b,c三个变量,而操作数栈中现在容量为2,那么咱们开端履行每一步字节码。
至于最后一行字节码,其实从助记符中能够明显的判断出,办法回来结束了~就不特意贴图了
(从第八张图开端,因为换了分辨率去制图,所以字体变小了,将就看。。)
看完整个履行进程最直观的咱们能看出以下几点:
- 字节码大部分时分占1位
- 局部变量表中暂存数据,字节码中不负责保存
- 操作基本都是根据操作数栈进行操作
既然咱们要作比照,根据栈和根据寄存器的差异是什么?那么接下来就来讲讲寄存器履行逻辑的进程,然后再作一个比照~
4.ART是怎样根据虚拟寄存器履行字节码文件的?
4.1 结构改动
比照根据栈,根据寄存器的虚拟机栈帧构成如下:
咱们能够看出:
- 没有了操作数栈、被虚拟寄存器替代了、
- 也没有了变量表
- 保留了程序计数器
乍一看如同做了不少减法,直观的感受到履行时占用内存的减少。
ok,了解栈帧中的改动,那么接着看咱们根据寄存器的字节码有哪些改动。
4.2 字节码改动
咱们能够直观的看出指令数减少了,可是每个字节码从占用一个字节升级到两个字节,接着咱们看看寄存器是怎样履行逻辑的~
4.3 解寄存器是怎样履行逻辑的?
最后一步也不贴了,便是return办法~
那么咱们能够明晰的感知到,因为栈帧结构改动,没有了局部变量表,所以字节码中不需求再履行将数据保存到变量表相关的操作,大大的减少了流程,可是咱们看最后一张图,有没有发现少了什么?
办法中 var a的值不见了!
不要慌,这其实是编译优化,咱们以最少的寄存器为条件,不改动语意,优化掉无用的代码。
ok,了解了他们的栈帧结构、字节码差异、履行逻辑后,咱们进入比照环节!
5.比照环节
直接总结好~上图表!
比照项 | 根据栈 | 根据寄存器 |
---|---|---|
字节码单元长度 | 8位(1字节) | 16位(2字节) |
单条指令长度 | 短 | 几乎翻倍 |
相同逻辑指令条数 | 多 | 少 |
相同逻辑数据移动次数 | 多 | 尽可能少 |
相同逻辑临时成果存储次数 | 多 | 尽可能少 |
所以为什么Android渠道根据寄存器的规划?
- 指令条数少,所以履行的功率更快!
- 数据移动次数少、临时成果存放次数少,所以更省内存和履行功率更快!
- 映射真实机器的寄存器,所以履行功率更快!
以上便是《为什么Android渠道虚拟机根据寄存器的规划?》的全部内容,觉得本片文章有用的童鞋们记得点赞!重视!收藏!,不要小气你们的称誉啦啦啦啦啦