Theme NexT works best with JavaScript enabled
0%

书籍阅读[虚拟机设计与实现]

^ _ ^

前言

书名全称为:虚拟机设计与实现(以JVM为例),为李晓峰所著。

虚拟机简介

什么是虚拟机

百度百科上对于虚拟机的定义是:虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。
但在本书中,将虚拟机分为了两类,一是模拟器,二是语言运行时引擎

  • 模拟器又细分为两类
    • 一是提供完整计算机系统模拟的完整指令架构(ISA)虚拟机,符合百度百科的虚拟机定义
    • 二是提供用户进程ABI模拟的应用程序二进制接口(ABI)虚拟机
  • 语言运行时引擎也细分为两类
    • 一是虚拟ISA虚拟机。虚拟ISA通常定义了一套高层的、规模有限的ISA语言;提供的运行时引擎使虚拟ISA编码的应用程序在其上执行
    • 二是语言虚拟机,提供一个运行时引擎来执行以客户语言编写的程序。程序通常以客户语言的源码形式提供给虚拟机,运行时引擎去解释或翻译程序,也就对应着解释器编译器

作者提到,本书的主题是 语言运行时引擎

为什么需要虚拟机

  • (计算机)安全性
  • (编程)效率
  • (应用程序)可移植性

安全语言的条件

  • 内存安全:确保内存中某种类型的数据总是遵循对这种类型的限制。例如:指针变量永远不会持有非法指针,数组元素永远不会越界
  • 运算安全:确保内存中某种数据的运行总是遵循对这种类型的限制。例如:指针变量不允许进行任意算术运算。
  • 控制安全:确保代码的执行流既不会卡住也不会跑飞。例如:跳转到恶意代码。

虚拟机示例

  • JavaScript引擎:存在于Web浏览器中,最早的JavaScript引擎是Mozilla Firefox的SpiderMonkey。2015年版本的JavaScript引擎工作步骤为:将JavaScript代码翻译为字节码形式的IR(Intermediate representation,中间表示),然后调用IonMonkey把字节码编译为机器码。
  • Perl引擎:Perl虚拟机本质上是一个解释器,其工作步骤为:第一阶段将Perl源码翻译为一系列操作码(称为op code或者字节码),第二阶段一步步遍历op code序列来执行它们。
    • 一般传统脚本语言虚拟机就是类似Perl引擎的解释器
    • 常见的脚本语言有:UNIX Shell、Windows PowerShell、Perl、Python、Ruby
    • 脚本语言通常以“编写 -> 执行”这样的交互方式使用。交互执行意味着程序执行一行代码,然后等待程序员输入下一行代码来执行。
    • 脚本语言也常用于批量执行或自动执行一系列任务
  • Android Java VM:Google Android是一种用于智能设备的操作系统。Android应用程序的主要编程语言是Java的一种变体。
    • 第一阶段Java程序被编译为JVM字节码;第二阶段JVM字节码被翻译为另一种形式的字节码,称为dex(Android应用程序以打包dex字节码的形式发布)。
    • 智能设备执行Android程序时,需要虚拟机来执行dex代码
      • Kitkat版本前的Android版本中,虚拟机名为Dalvik,它包含一个解释器以及一个即时编译器。其工作流程为:Dalvik首先用解释器执行dex代码,并维护一个计数器来记录同一dex代码片段的执行次数。当某一dex片段执行次数超过某一阈值时(说明该段代码频繁使用)。Dalvik就会调用编译器将这段代码编译为机器码,然后下次就可以直接执行机器码来提高性能
      • Kitkat版本后的Android版本中,虚拟机名为ART(Android Runtime)。ART在应用程序安装到设备上时就把dex代码编译为机器码,编译后的代码缓存在持久存储中,这种方法称为预编译AOT(Ahead Of Time)。ART用更长的安装时间换得了更快的应用程序启动
  • Apache Harmony:一个由Apache软件基金会和社区贡献者开发的一个开源Java实现。它包括一个名为动态运行层虚拟机的JVM实现。
    • Apache Harmony项目本身已在2011终止
    • 实现完整的Java平台,特别是那些大量的类库,需要巨大的工作量。但实现一个JVM则相对容易一些。据作者所知,已经有十几个声明对外发布的JVM实现,但独立的Java类库实现只有3个:OpenJDK、GNU Classpath、Apache Harmony。目前,OpenJDK库实现可能是唯一一个仍在活跃维护中的Java类库

虚拟机的内部组成

一个完整的语言实现通常至少包括3部分:

  • 虚拟机 :对于JVM来说,就是字节码的运行时引擎
  • 语言库 :语言的核心库。除非是非常底层且非常原始的语言(比如针对某个特定处理器的汇编语言),否则一个常用语言的实现通常会把这个语言的核心库作为虚拟机的一部分包含进去。
    • 有时候,虚拟机不得不硬编码一些只能用于关联库的逻辑。例如,JVM不能没有库程序包java.lang
    • 这是因为有些核心数据结构,如Java对象和Java类,依赖于程序包java.lang.Object以及java.lang.Class的定义
  • 工具集 :为了应用某个语言开发程序,通常需要针对这个语言的工具集与虚拟机合作,以支持调试、性能分析、打包等等功能。

虚拟机核心组件

同一语言的不同虚拟机实现可能在各个方面大有不同,但必须遵循并支持同一语言标准。因此,每个实现必须包含一系列功能类似的核心组件

一个虚拟机的实现需要完成如下功能:

  • 把应用程序的代码加载到内存中(加载器),并把符号解析到内部地址(动态链接器
  • 执行程序操作(执行引擎
  • 管理各种计算资源,包括内存(内存管理器)和处理器(线程调度器
  • 为该语言不能直接访问的外部资源提某种访问方式(语言扩展/本地接口

加载器与动态链接器