文明之精神,野蛮之体魄。
全部博文(64)
分类: LINUX
2013-05-13 13:53:20
应用程序虚拟机的各个方面
在应用程序虚拟化领域中,VMs 用于提供一个独立于硬件的环境来执行应用程序。例如,看一下图 1。最顶部是高级语言,开发人员使用该语言构建应用程序。通过一个编译过程,该高级代码被编译成一个名为对象代码 的中间表示。在一个非虚拟化环境中,该对象代码(独立于机器)被编译成要在物理平台上执行的本机代码。但是在一个应用程序虚拟化环境中,对象代码在一个抽象机器内经过解译,以便于执行。这里的主要优势在于,可以在支持抽象机器(interpreter)的任何硬件平台上执行同样的对象代码。
图 1. 实现平台独立性的应用程序 VM除了创建一个在其中执行对象代码的可移植环境之外,应用程序虚拟化提供一个环境来隔离 VM 与运行在主机上的其他应用程序。该设置具有大量优势,比如详细的资源管理和安全性。
VM 的对象代码也称为 bytecode,特别定义解释程序执行的一个指令集。bytecode 一词从这样的实现演变而来,即出于简便和性能考虑将其虚拟机指令集有效实现为单一字节。
现在我们看一下应用程序虚拟化的一些历史使用情况,并探究其一些现代化的用途。
虚拟机的历史
应用程序虚拟化最早于 20 世纪 60 年代用于 Basic Combined Programming Language (BCPL)。BCPL 是 Martin Richards 在剑桥大学开发的一种命令式语言,是 B 语言的一个前身,后来该语言发展为我们现在使用的 C 语言。
尽管 BCPL 是一种高级语言(类似于 C),编译器生成的中间代码叫做 O-code(对象代码)。O-code 可在物理机上解译(为 VM),或从 O-code 编译为主机的本机语言。该功能在机器独立性环境中提供了大量优势。首先,通过从物理机提取 O-code,可以在各个主机上轻松解译它。其次,可将 O-code 解译为本机语言,这将允许开发将 O-code 翻译为本机指令的一个或多个编译器(一个较简单的任务)。这个机器独立性使得语言可在各个机器之间移植,从而因为可用性而受到欢迎。
在 20 世纪 70 年代早期,圣地亚哥的加州大学实现了用于执行编译的 Pascal 的 VM 方法。它们将中间表示称为 p-code,它寻求底层硬件的独立性来简化 Pascal 编译器的开发(而非依赖于抽象的伪机架构)。Forth 语言也适用于 VM,即零地址或基于堆栈的架构。
在 1972 年,Xerox PARC 引入了 Smalltalk 语言,该语言依赖于 VM 来执行。Smalltalk 是围绕对象概念构建的第一批语言之一。Smalltalk 和 p-code 都大大影响了目前存在的最突出的基于 VM 的语言之一:Java 语言。Java 最早出现于 1995 年,由 Sun Microsystems 开发,并通过 Java 虚拟机萌发了独立于平台的语言之一构想。从那时起,Java 技术就成为 web 应用程序的一个构建块。从服务器端脚本到客户端 applets,Java 技术提高了对 VM 技术的认识,并引入了较新的技术,该技术使用准时制生产(JIT)编译技术桥接了解译与本机执行。
很多其他语言包含 VMs 的概念。Erlang 语言(由 Ericsson 开发)使用一个 VM 来执行 Erlang bytecodes,且通过源的抽象语法树解译 Erlang。轻量级 Lua 语言( 在巴西里约热内卢天主教大学开发)包含一个基于寄存器的 VM。当执行一个 Lua 程序时,将其翻译成 bytecodes,然后在 VM 中执行。本文稍后探究可用于任何语言的一个 bytecode 标准。
今天的虚拟机
使用 VMs 提供对物理主机的抽象是历史上一种常见的方法,现在经过发展有了新的应用。我们看看将 VM 的概念推向未来的一些较新的开源解决方案。
Dalvik VM
Dalvik 是由 Google 为 Android 操作系统开发的一项开源 VM 技术。Android 是经过改进的 Linux 内核,为移动设备纳入一个软件栈(见图 2)。不同于许多依赖于基于软件栈的架构的 VM 技术,Dalvik VM 是一个基于寄存器的虚拟架构(参见 参考资料 了解有关架构和指令集的更多信息)。尽管基于软件栈的架构在概念上很简单有效,它们会引入新的效率低下问题,比如较大的程序规模(因为要对软件栈进行维护)。
Because Dalvik 是 VM 架构,它依赖于编译成 VM 理解的 bytecodes 的一种高级语言。Dalvik 没有白费力气做重复工作,而是依赖于 Java 语言作为应用程序开发的高级语言。Dalvik 还依赖于一种称为 dx 的特殊工具来将 Java 类文件转化成 Dalvik VM 可执行文件。为了提高性能,VM 可能进一步改进 Dalvik 可执行文件(dex)便于进一步优化,包括 JIT 编译,它为提供本机性能而将 dex 指令翻译成本机指令。这个过程也称为动态翻译,是用于提高 VM 技术的性能的一项流行技术。
如 图 2 所示,一个 Dalvik 可执行文件(以及 VM 的一个实例)被孤立为 Linux 用户空间中的单一进程。Dalvik VM 旨在支持同时执行多个 VMs(在独立进程中)。
Dalvik VM 不是在标准的 Java 运行时上执行的,因而不继承其上的许可。而 Dalvik 是 Apache 2.0 许可下的一个洁净室(clean-room)实现。
Parrot
另一个有趣的开源 VM 项目是 Parrot。Parrot 是另一个基于寄存器的 VM 技术,旨在有效执行动态语言(在运行时执行某些常常在编译时执行的操作的语言,比如修改类型系统)。
Parrot 最初被设计为 Perl6 的一个运行时,不过是一个灵活的环境,可为多种语言执行 bytecodes(见图 3)。Parrot 支持多种输入格式,包括 Parrot Abstract Syntax Tree (PAST),这对于编译器创建者很有用;Parrot Intermediate Representation (PIR) 是一种高级表示,可由人或由编译器自动编写;还有 Parrot Assembly (PASM),它在中间表示下面,对于人员和编译器都很有用。每种形式都在 Parrot VM 上被翻译成 Parrot bytecode 并加以执行。
Parrot 支持大量语言,但是让其如此有趣的一个方面是它同时对静态和动态语言的支持,包括对功能语言的特定支持。清单 1 显示 PASM 的简单使用。要使用 Ubuntu 安装 Parrot,只需使用 apt-get:
sudo apt-get install parrot |
下一环节说明 Parrot 中一个简单的字符串处理程序。注意,尽管 Parrot 将该代码作为程序集加以实现,它比您习惯使用的程序集功能丰富多了。Parrot 中的指令使用 dest,src 语法,因此清单 1 显示使用文本加载的字符串寄存器。length 指令确定字符串的长度并将其加载到一个整数寄存器中。print 指令发出标准输出(stdout)的参数,且 concat 实现字符串连接。
$ more test.pasm set S1, "Parrot" set S2, "VM" length I1, S1 print I1 print "\n" concat S3, S1, S2 print S3 print "\n" end $ parrot test.pasm 6 ParrotVM $ |
您会在 Parrot 内找到丰富的指令集(参见 参考资料 了解更多信息)。创建者选择功能的丰富性胜过简约性,因而更易于为 Parrot VM 编码和构建编译器。
即使拥有 PASM 提供的高级抽象,PIR 更适合高级程序员。清单 2 提供用 PIR 编写、由 Parrot VM 执行的示例程序。该例声明一个名为 square 的子例程,计算某个数字的平方数并返回该数字。该进程被主子例程(标为 :main 以告诉 Parrot 首先运行它)调用以打印结果。
$ more test.pir .sub square .param int arg arg *= arg .return(arg) .end .sub main :main .local int value value = square(19) print value print "\n" .end $ parrot test.pir 361 $ |
Parrot 提供丰富的应用程序虚拟化环境来高效地开发独立于机器的应用程序。您可以找到大量支持专为 Parrot 设计的编译器前端的语言,包括 C、Lua、Python、Scheme、Smalltalk 等等。
应用程序虚拟机的其他用途
到目前为止,您了解了应用程序虚拟化的历史用途,包括两个最近的示例。Dalvik 正在推动当前手机内的应用程序开发,且 Parrot 为编译器创建者提供一个用于静态和动态语言的高效框架。不过应用程序虚拟化的概念正在迄今为止探讨过的方法以外的大量其他领域得到实现。
一个特别有趣的用途很可能在您目前使用的计算机上看到。使用新 Extensible Firmware Interface (EFI) 的系统是一个 BIOS 替代品,可以在 EFI Byte Code (EBC) 中实现固件驱动程序。系统固件包括一个解释程序,在加载 EBC 映像时会调用该程序。该概念也在 Open Firmware 中由 Sun Microsystems 使用 Forth(包含其自身 VM 的一种语言)得到实现。
在游戏界,应用程序虚拟化的使用并不是新的东西。许多现代游戏包括非玩家控制角色行为的脚本化和使用执行 bytecodes(比如 Lua)的语言的其他游戏方面。不过游戏中的应用程序虚拟化概念其实要追溯到更远。
Infocom,一家引入 Zork 等基于文本的冒险游戏的公司,在 1979 年看到了机器独立性的价值。Infocom 创建了一个名为 Z-machine(以 Zork 命名)的 VM。Z-machine 是允许冒险游戏更轻松地移植到其他架构的一个 VM。无需将整个冒险游戏移植到一个新系统,代表 Z-machine 的一个解释程序会被移植。该功能简化了到其他系统的移植过程,这些系统可能有不同的语言支持和完全不同的机器架构。尽管 Infocom 的目标是省去每天在架构之间移植的麻烦,他们的工作是继续简化移植并使这些游戏可进入新一代(甚至在移动平台上)。
VMs 的其他游戏应用程序包括 ScummVM(它提供一个 VM 环境供 Maniac Mansion (SCUMM) 脚本语言的脚本创建工具使用)(创建于 1987 年)。SCUMM 由 LucasArts 创建用于简化图形冒险游戏的开发。ScummVM 现在用来在各个平台上玩大量文本和图形冒险游戏。
展望
就像平台(或系统)改变了我们配置和管理服务器和桌面的方式一样,应用程序虚拟化继续提供有效的机制来从其主机系统提取应用程序。鉴于该方法的普及,了解促使应用程序虚拟化更加灵活高效的软硬件的演化会很有趣。