Android里的虚拟机
Android里的虚拟机, 旨在向大家简易叙述虚拟机里的一些知识
文章目录
前言
Android里的虚拟机, 旨在向大家简易叙述虚拟机里的一些知识。一、虚拟机(jvm)是什么?
- Java虚拟机(JVM)是Java Virtual Machine的缩写,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能模拟来实现的。Java虚拟机有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。
- 引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。
总的来说,它的作用是把平台无关的.class里的字节码翻译成平台相关的机器码,这样就实现了跨平台运行,如我们Android平台的虚拟机有Dalvik和Art虚拟机。
二、jvm和Android虚拟机
千言万语不及一张图,所以上图!
从图上可以清楚的分析出
我们先来看一下class和dex的区别。
参考:Dex文件格式详解
jar文件里有多个class,而dex文件里只有几个数据区(每个区相当于一个list)。可以看到,当java程序编译成class后,使用dx工具将所有的class文件各个部分(成员变量,方法,常量等)整合到一个dex文件,目的是其中各个类能够共享数据,在一定程度上降低了冗余,同时也是文件结构更加经凑。dex将原来class每个文件都有的共有信息合成一体,这样减少了class的冗余。
dex和class的区别:
- dex文件减少了整体的文件尺寸,像是一种压缩文件,一个dex文件可以表示更多的class,而class是一种简单单一的文件。
- Android虚拟机加载类时,只需要一次IO就可以加载很多类,而class需要多次IO,dex文件提高了Android虚拟机的查找速度。
- dex指令更加密集,class指令多。(下文会分析)
- dex因为寄存器设计方便寻址,class是虚拟栈需要多次load和store指令(下文会分析)
- dex适合移动设备,而class适合pc。
2.class文件存在很多冗余的信息,dex工具能把这些冗余信息去除。
int a = 10;
int b = 15;
int c = a + b;
虚拟栈(1个字节):
这段程序执行的顺序肯定是从上往下执行,可以把这段代码看作一个栈,当int a = 10;
执行完就出栈了,依次按顺序出栈,且需要更多的指令(load和store),占用比较多的cpu时间。
寄存器:
可以这么理解 每段代码都会有不同的引用,这样指令可以执行的更加快速,因为毕竟虚拟栈还是一个栈,执行必须按步执行,执行效率低。但因为是引用的关系,我们肯定是要去寻址的(源地址和目标地址),所以这样就导致了指令长度就变成了2~3个字节,这就意味着需要更多的指令空间意味着数据缓冲(d-cache)更容易失效。
jvm这种没有地址(无变量申明)指令更紧凑,但完成操作需要更多的load/store指令,也意味着更多的指令分派(instruction dispatch)和内存访问次数,访问内存是执行速度的一个重要瓶颈。
Android虚拟机二地址或三地址指令虽然每条指令占的空间比较多,但总体来说可以用更少的指令完成操作,指令的分派与内存访问次数都比较少。
3.Android虚拟机基于寄存器,而jvm是基于虚拟栈的。
那栈到底是什么?程序的执行原理是什么?
我们首先需要了解同一段代码分别在Android虚拟机和JVM的运行原理。
public class Demo {
public static void foo() {
int a = 1;
int b = 2;
int c = a + b;
}
}
我们就看这段代码好了。
我们用javap命令查看jvm里的代码。
生成的jvm指令如下
Classfile /C:/Users/13703/Desktop/Demo.class
Last modified 2021-1-14; size 356 bytes
MD5 checksum c88a56df3f58652012d9e23851ab830c
Compiled from "Demo.java"
public class Demo
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#18 // java/lang/Object."<init>":()V
#2 = Class #19 // Demo
#3 = Class #20 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 LDemo;
#11 = Utf8 foo
#12 = Utf8 a
#13 = Utf8 I
#14 = Utf8 b
#15 = Utf8 c
#16 = Utf8 SourceFile
#17 = Utf8 Demo.java
#18 = NameAndType #4:#5 // "<init>":()V
#19 = Utf8 Demo
#20 = Utf8 java/lang/Object
{
public Demo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LDemo;
public static void foo();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=0
0: iconst_1 ––––––––––- 将int型1推至栈顶
1: istore_0 ––––––––––- 将栈顶int型数值存入本地变量(本地变量表),位置0
2: iconst_2 ––––––––––- 将int型2推至栈顶
3: istore_1 ––––––––––- 将栈顶int型数值存入本地变量(本地变量表),位置1
4: iload_0 ––––––––––- 将本地变量第0个int型推送至栈顶
5: iload_1 ––––––––––- 将本地变量第1个int型推送至栈顶
6: iadd ––––––––––- 将栈顶两int型数值相加并将结果压入栈顶
7: istore_2 ––––––––––- 将栈顶int型数值存入本地变量(本地变量表),位置2
8: return ––––––––––- 从当前方法返回void
LineNumberTable:
line 3: 0
line 4: 2
line 5: 4
line 6: 8
LocalVariableTable:
Start Length Slot Name Signature
2 7 0 a I
4 5 1 b I
8 1 2 c I
}
SourceFile: “Demo.java”
所以jvm指令有很多的load/store。
我们再来生成android虚拟机里的指令。
我们需要借助Andrid sdk 里的 build-tools下的任意一个版本的dx.bat工具。
Demo.foo:()V:
regs: 0003; ins: 0000; outs: 0000
0000: code-address
0000: local-snapshot
0000: code-address
0000: code-address
0000: local-snapshot
0000: const/4 v0, #int 1 // #1 --------------------- 申明一个变量v0 (4个字节) 赋值1
0001: local-start v0 "a": int
0001: const/4 v1, #int 2 // #2 --------------------- 申明一个变量v0(4个字节)赋值2
0002: local-start v1 "b": int
0002: add-int v2, v0, v1 --------------------- 把v0+v1赋值给v2
0004: local-start v2 "c": int
0004: code-address
0004: code-address
0004: local-snapshot
v0 "a": int
v1 "b": int
v2 "c": int
0004: return-void --------------------- 返回空
0005: code-address
debug info
line_start: 3
parameters_size: 0000
0000: prologue end
0000: line 3
0001: line 4
0001: +local v0 a int
0002: line 5
0002: +local v1 b int
0004: line 6
0004: +local v2 c int
end sequence
source file: "Demo.java"
很明显 ,我们可以从视觉的感觉到Android虚拟机里的指令(arm指令)少的多了。
后面添加了-----------------这个为有用的代码,其他都是dex工具自动给我们生成的代码。
而Android虚拟机又有分别:
- Dalvik虚拟机
使用JIT(Just In Time),每它实时的将一部份就把dex字节码翻译成机器码,所以安装的时候比较快,但我们每次都要编译加运行,这样会拖慢应用以后启动的效率。 - Art虚拟机
使用AOT(Ahead of Time),故名思意,在应用安装的期间,就把dex字节码翻译成机器码存在设备上,所以应用占用的空间会有所增大,但这样应用程序每次运行就不用重复编译了,启动就快了,从而减少了cpu的使用,改善了电池的续航。
总结
1.1.1Jvm,Dalvik与Art三者之间的区别
1.2.1 JVM虚拟机与Android虚拟机区别
Android虚拟机执行的是.dex格式文件 jvm执行的是.class文件
class文件存在很多的冗余信息,dex工具会去除冗余信息
Android虚拟机是基于寄存器的虚拟机 而jvm执行是基于虚拟栈的虚拟机
1.2.3 Art虚拟机与Dalvik虚拟机区别
Dalvik下,应用每次运行都需要通过即时编译器(JIT)将字节码转换为机器码,即每次都要编译加运行,这虽然会使安装过程比较快,但是会拖慢应用以后每次启动的效率。
而在ART 环境中,应用在第一次安装的时候,字节码就会预编译(AOT)成机器码,这样的话,虽然设备和应用的首次启动(安装慢了)会变慢,但是以后每次启动执行的时候,都可以直接运行,因此运行效率会提高。
典型的 空间换时间 128G —>apk
ART占用空间比Dalvik大(字节码变为机器码之后,可能会增加10%-20%),这也是著名的“空间换时间大法"。
Art预编译也可以明显改善电池续航,因为应用程序每次运行时不用重复编译了,从而减少了 CPU 的使用频率,降低了能耗。
1.2.1那dex和class到底在结构上的区别
- dex文件减少整体的文件尺寸 dex更像是一种压缩文件,一次可以表示更多的class。class像是一种单个文件
- Android虚拟机加载类时 只对dex需要一次IO可以加载很多新类,而class需要加载多次IO,Android虚拟机提高查找速度
- dex指令更加密集 。class指令比较多
- dex 寄存器设计方便寻址,class java栈需要更多次load与store指令
- dex适合于移动设备,性能不太高的要求。class适合PC大内存,单指令小的情况下可以快速执行
1.4.1 Android虚拟机中寄存器起什么作用,与栈的区别在哪里(又或者基于栈与基于寄存器的架构,谁更快?)
原因是:虽然没有地址(无变量声明)指令更紧凑,但完成操作需要更多的load/store指令,也意味着更多的指令分派(instruction dispatch)次数与内存访问次数;访问内存是执行速度的一个重要瓶颈,二地址或三地址指令虽然每条指令占的空间较多,但总体来说可以用更少的指令完成操作,指令分派与内存访问次数都较少。
1.5.1Arm指令究竟是什么指令,与字节码指令的区别
字节码指令 和 Arm指令内容是不一样
如 同样一个 a+b
在 jvm的指令 iadd idiv imul
但是在dalvik指令是 add-int mul-int
arm指令是由arm公司开发的。 指令含有地址,而字节码指令没有地址
字节码指令是 sun公司开发,简单高效
1.6.1为什么Art虚拟机比Dalvik虚拟机运行速度高
(1)在Dalvik下,应用每次运行都需要通过即时编译器(JIT)将字节码转换为机器码,即每次都要编译加运行,这虽然会使安装过程比较快,但是会拖慢应用以后每次启动的效率。而在ART 环境中,应用在第一次安装的时候,字节码就会预编译(AOT)成机器码,这样的话,虽然设备和应用的首次启动(安装慢了)会变慢,但是以后每次启动执行的时候,都可以直接运行,因此运行效率会提高。
(2)ART占用空间比Dalvik大(字节码变为机器码之后,可能会增加10%-20%),这也是著名的“空间换时间大法"。
(3)预编译也可以明显改善电池续航,因为应用程序每次运行时不用重复编译了,从而减少了 CPU 的使用频率,降低了能耗。
ARM指令集
系统性能的显著提升
应用启动更快、运行更快、体验更流畅、触感反馈更及时
更长的电池续航能力
支持更低的硬件
转载: https://blog.csdn.net/sunlifeall/article/details/112489978
更多推荐










所有评论(0)