与 Java 虚拟机 (JVM) 类似,.net CLR 是一个字节码解释虚拟机。
JVM 解释包含 java 字节码的程序,.net CLR 解释包含微软所谓的“中间语言 (IL)”指令的程序。这些字节码之间存在差异,但虚拟机是相似的,并渴望提供相似的功能。
这两种虚拟机实现都能够将它们的输入字节码编译成它们正在运行的计算机的机器语言。这称为“即时编译 (JIT)”,生成的输出代码称为“JIT 代码”。由于 JIT 代码包含计算机 CPU 机器语言的指令序列,因此该代码有时被称为“本机”代码。
但是,JIT 代码在质量和数量上与本机代码不同,如下所述。出于这个原因,本文认为 JIT 代码只不过是运行特定字节码程序时虚拟机的本机实现。
这两种虚拟机 (VM) 都希望提供的一项功能是以防止某些危险编程错误的形式提供的安全性。例如,这个网站论坛的标题 stackoverflow 的灵感来自于本机代码中可能存在的一种此类危险错误。
为了提供安全性和执行安全性,VM 在“虚拟机级别”实现类型安全。需要分配给 VM 内存来存储保存在该内存位置中的数据类型。例如,如果一个整数被压入堆栈,就不可能从堆栈中弹出一个双精度数。禁止 C 风格的“联合”。禁止指针和直接访问内存。
如果结果是诸如 EXE 文件之类的本机二进制文件,我们无法通过对开发人员实施面向对象的语言框架来获得相同的好处。在这种情况下,我们将无法区分使用框架生成的本机二进制文件和恶意用户使用框架以外的源生成的 EXE。
在 VM 的情况下,类型安全是在程序员被允许访问的“最低级别”强制执行的。(暂时忽略可以编写托管的本机代码。)因此,没有用户会遇到执行需要直接访问内存位置和指针的危险操作之一的应用程序。
在实践中,.net CLR 实现了一种编写本机代码的方法,可以由 .net“托管”代码调用。在这种情况下,本机代码作者有责任不犯任何指针和内存错误。
由于 JVM 和 .net CLR 都执行 JIT 编译,因此任何一个 VM 实际上都会从提供的字节码创建一个本机编译的二进制文件。这种“JIT 代码”的执行速度比 VM 的解释器执行速度更快,因为即使是由 JIT 生成的机器语言代码也包含 VM 需要执行的所有 VM 安全检查。因此,JIT 输出代码不如本机代码快,本机代码通常不包含大量运行时检查。然而,这种速度性能缺陷被换成了对可靠性(包括安全性)的改进;特别是,防止使用未初始化的存储,强制分配的类型安全,执行范围检查(因此防止基于堆栈和堆的缓冲区溢出),对象生命周期由垃圾收集管理,动态分配是类型安全的。