虚拟机是一种高级抽象,对于原生操作系统来说,模拟了物理机。
虚拟机是对于原生操作系统来说的一种高级抽象,对物理机进行了仿真;
对于虚拟机来说,可以使能多个操作系统和硬件架构;
java 和 python 的 解释器可以作为举例说明;这两种语言的代码,被编译成他们对应虚拟机的字节码。
同样,我们可以看到 微软的 .net 架构,他的代码被编译成了一种中间语言,为了 CLR 通用语言进行时;
虚拟机的实现都需要什么呢?
他应该仿真一些物理机的什么操作呢?
- 从源码编译到虚拟机的对应字节码(字节码理解为一种在虚拟机上可以直接运行的指令)
- 包含 指令和操作数的 数据结构
- 函数的调用栈
- 指令指针,我理解为 pc,程序计数器;下一条指令应该往哪跳;
- 虚拟的 CPU – 指令调度器
- 取指令
- 解码
- 执行
这里有两种基本的虚拟机实现方式
- 栈式
- 先进后出
- 可以理解为函数调用
- java/.net 都是栈式虚拟机
- 寄存器式
- 比较容易理解
- add c,a, b
- c = a + b
- lua 和 dalvik 是寄存器式虚拟机
分别用小例子来理解一下。
栈式虚拟机
- 首先,数据都存储在一个栈里
- 通过 pop 和 push 对 栈 进行数据操作
- LIFO last in first out 风格
我们以 c = a + b 来举例
说明一下
- sp 相当于栈顶指针 stack pointer
a = 20
b = 7
c 是我们想要的结果
那么栈式虚拟机的操作应该是这样的;
- pop 20 取数据
- pop 7 取数据
- add 20, 7 result 计算
- push result 把结果写回到栈里,留作备用;
- 栈式虚拟机的一个特点,隐式寻址,因为你取数据的时候,都是从栈顶拿到的,因此sp这个指针是最常用的。
- 那么相对于寄存器式虚拟机来说,存储空间就会少一些。
寄存器式虚拟机
- 数据结构 是 寄存器
- 没有 pop ,push
- 但是需要 地址 来显式寻址,就是说直接有一个 0x000a 之类的地址。
也是一个加法操作,就是 把 R1 和 R2 的值 加起来,放到R3里就ok了;
add R1,R2,R3
这个看起来是简单并且直接的。
- 没有栈式中 pop 、 push 的开销
- 指令调度循环时,执行起来会比较快。
- 还有一个优势,可以进行一些优化,栈式虚拟机却不能;
- 比如 通用子表达式的消除,减少生成指令的行数。
寄存器式虚拟机 相对于 栈式虚拟机 来说, 指令会比较长。 因为我们要显示寻址,而栈式仅需要一个 栈顶指针就好了。
The DALVIK virtual machine
google 出品,for Ardroid OS;
- Android 的 kernel 为 linux
- 负责操作系统的核心,如文件系统,设备管理,网络,进程调度
- dalvik 相当于 kernel 的一部分,与runtime 对接,每个Android的app 在 dalvik 上都有一个单独的实例,如果一个crash,不会影响其他的app。
- 启动boot loader,把Linux kernel 放到 内存中
- linux kernel 运行 init 代码,他是所有进程的父进程
- init 程序 会 启动系统监控程序 和 zygote 服务
- zygote 服务 会 创建一个 dalvik 实例,这个实例是所有其他实例的爸爸2333
- zygote 同样会 设置一个 bsd 监听程序,监听 要来的请求。
- 当dalvik 虚拟机 收到了一个要创建实例的请求时,那么这个 实例爸爸,就 fork一个子实例给那个所请求的Application。
Android 程序一般都是 java作为源代码编写,通过javac 来编译成 java 的 bytecode,正常情况下,java byte code 就可以在jvm上执行了。但是要在Android上执行的话,还得继续编译成 dalvik 的 bytecode;所以 右边 还得加上一步 dex compiler 的处理,才能再执行。
Reference
应为原文
知乎讨论什么时候需要 栈 还是 寄存器 式的 虚拟机。