CLR是虚拟机吗?

thi*_*eek 51 .net clr vm-implementation

我读过一本书,将.net CLR称为虚拟机?谁能证明这一点?我们在某些开发平台上需要虚拟机概念的原因是什么?

是不是可以开发一个完全面向对象并且像.net一样强大的本机框架[没有虚拟机的框架]?

将CLR称为虚拟机的书是" Professional .Net Framework 2.0 ".

Joe*_*orn 92

这里有很多误解.我想你可以把.Net想象成一个虚拟机,但是让我们来看看.Net Framework如何真正处理你的代码.典型情况看起来像这样

  1. 您使用C#,VB.Net,F#或其他一些兼容语言编写.Net程序.
  2. 该代码被编译为中间语言(IL),类似于Java的字节码,分发给最终用户机器.
  3. 最终用户首次在安装了正确版本的.Net的计算机上调用该程序
  4. 计算机看到这是一个.Net程序集而不是"原始"机器代码,并将其传递给JIT编译器
  5. JIT编译器将IL编译为完全本机的机器代码.
  6. 本机代码在程序执行期间保存在内存中.
  7. 调用保存的本机代码,IL不再重要.

这里有几个重点,但最重要的一点是,任何代码都不会被解释.相反,您可以在步骤5中看到它被编译为本机代码.这比将其加载到虚拟机中有很大的不同,原因如下:

  1. 完全编译的代码由cpu直接执行,而不是由另外的软件抽象层解释或翻译,这应该更快.
  2. JIT编译器可以利用特定于运行程序的单个机器的优化,而不是确定最低公分母.
  3. 如果你想要你甚至可以预编译代码,实质上完全隐藏了用户的第5步.

我想你可以称之为虚拟机,在某种意义上,JITter从开发人员中抽象出真机的细节.我个人认为这不是正确的,因为对于许多人来说,虚拟机意味着远离本机代码的运行时抽象,而.Net程序就不存在.

关于整个过程的另一个关键点是,它真正使它与"虚拟机"环境区分开来,它只是典型的过程.如果您真的想要,可以在分发之前预编译.Net程序集,并将本机代码直接部署到最终用户(提示:在程序的整个生命周期中,它的总体速度较慢,因为您丢失了特定于机器的优化).当然,您仍然需要安装.Net运行时,但此时它与其他任何运行时API都没有太大区别; 它更像是一个带有可以链接的漂亮API的集合dll,正如您可能拥有的VB或C运行时一样,Microsoft也附带了Visual Studio.这种情况使IL脱离了图片,使VM名称更难以证明.(我说"有点"因为IL仍然被部署并用于验证保存的代码,但它本身从未触及执行).

另一个要点是缺乏VM进程.当您运行应用程序时,没有运行的常见"沙盒"进程.将其与Java进行比较,如果在程序运行时打开任务管理器,您将看到专门针对Java VM的进程,并且应用程序的实际进程是VM创建的沙箱内的线程.在.Net中,您可以直接在Windows任务管理器中查看应用程序的进程.

总结:你可以说IL + CLR + JIT以某种方式组成了一个虚拟机.就个人而言,我不这么认为,但如果你相信的话,我不会和你争论.我想说的是,当你告诉别人.Net在虚拟机中运行而没有进一步的解释时,你正在与那个人沟通的想法是"在主机进程中解释字节码".这是错的.

  • Joel,根据你的评论,我觉得你相信JIT编译器在应用程序启动时一劳永逸地编译IL代码到本机代码,然后突然停止.这是错误的,只要执行流程需要,JIT就会动态编译方法.此外,还有一个VM进程.这是运行您的应用程序的CLR.它绝对是一个沙盒环境,具有GC,安全模型和元数据服务.正在运行的应用程序仅以.exe命名,因为Window的PE加载程序知道如何委派给CLR .net二进制文件. (14认同)
  • @Joel,你的整个最后一段还是错的.Windows的PE加载器启动CLR,它本身在其控制,内存和安全方面启动程序.里面绝对可以使用.这只是一个黑客,以避免启动java,Rotor或单声道.但.net EE(执行引擎)控制程序的运行方式. (6认同)
  • 你似乎在说,如果它没有像Java那样完全一样,那么它就不是虚拟机.我认为这是我不同意你的最重要的事情,因为它往往是一个循环的定义. (5认同)
  • 乔尔,你的答案是跟随MS领导..net CLR是已停产的JVM的演变.当JIT输出的功能是复制CLR功能时,"IL + CLR + JIT"等于VM.我不理解你对一个得到很好回答的问题的奇怪攻击,包括重新提出一些断言:我的答案尚未得到回答,而你的答案似乎是"错误的".OP认为JVM是VM,因此.Net CLR也是VM.它们中的任何一个都不是虚拟机,因为它们不仅功能相同,而且来自另一个. (5认同)
  • 是的.PE Header重定向是一个引导CLR(mscoree)的技巧,它通过各种方式运行.Net应用程序.而且,就像JB所说的那样,JIT并不是一劳永逸地完成的,一些JITted方法甚至可以在以后被丢弃并重新安装.我猜这种错误观念在旁观者的眼中. (4认同)
  • 您是否从第二个列表中获得了第3项的参考?除非调用NGEN,否则我从未见过任何说明保存了预JITted代码的内容. (2认同)
  • 由于没有被进一步解释,您提出了关于 JIT 代码“更快”的观点 (1)。虽然这是真的,但它有点误导。代码的性能比典型的 C 项目更接近 VM 性能。差异在于 JIT 输出包含更多的运行时检查、类型安全检查,尤其是比典型的 C 项目更多的动态分配。我的比较不是为了进行值比较,而是从这个角度进行比较:JIT 输出的性能类似于 VM 代码,而不是写入非 VM API 的代码,无论是速度还是安全性。它就像一个虚拟机。 (2认同)
  • @Damien_The_Unbeliever:关于#3,这个参考表明只保存了 NGEN 的代码:http://msdn.microsoft.com/en-us/magazine/cc163655.aspx“注意这里的微妙权衡。使用 NGEN 意味着交易 CPU更多磁盘访问的消耗,因为 NGEN 生成的本机映像可能比 MSIL 映像大。您可能想知道这是否会影响冷启动,因为它会导致磁盘活动增加。有趣的是,CLR 性能团队已经观察到如果完全消除 JIT 编译,冷启动时间通常会得到改善。” (2认同)
  • .net框架只是一个库,本地用C/C++编写.然后添加到PE格式以设置dll或exe是否是.Net代码并且包含MSIL.Windows加载器确实在加载时将所有正在运行的代码编译成本机代码.它根据需要做的唯一事情是没有被引用的代码.例如,如果代码由于用户操作或某些事情而稍后在管道中加载另一个DLL,那么将按需编译JIT.现在.Net Native已经用完,你可以编译你的代码和它用于本机代码的.Net部分. (2认同)

Hea*_*utt 24

与Java虚拟机(JVM)类似,.net CLR是一个字节码解释虚拟机.

JVM解释包含java字节代码的程序,而.net CLR解释包含Microsoft称为"中间语言(IL)"指令的程序.这些字节代码之间存在差异,但虚拟机类似,并且希望提供类似的功能.

这两种虚拟机实现都能够将其输入字节码编译为运行它们的计算机的机器语言.这称为"及时编译(JIT)",生成的输出代码称为"JIT代码".由于JIT代码包含计算机CPU的机器语言中的指令序列,因此该代码有时称为"本机"代码.

但是,JIT代码在质量上和数量上与本机代码不同,如下所述.因此,本文将JIT代码视为运行特定字节码程序时虚拟机本机实现.

这些虚拟机(VM)希望提供的一个特征是以防止某些危险编程错误的形式的安全性.例如,本网站论坛的标题stackoverflow的灵感来自本机代码中可能出现的一种此类危险错误.

为了提供安全性和执行安全性,VM在"虚拟机级别"实现类型安全性.需要分配VM内存来存储该内存位置中保存的数据类型.例如,如果将整数推入堆栈,则无法从堆栈中弹出double.禁止使用C式"工会".禁止使用指针和直接访问内存.

如果结果是本机二进制文件(如EXE文件),则通过在开发人员上强制使用面向对象的语言框架,我们无法获得相同的好处.在这种情况下,我们将无法区分使用框架生成的本机二进制文件和使用除框架之外的源的恶意用户生成的EXE.

在VM的情况下,类型安全性在允许程序员访问的"最低级别"强制执行.(暂时忽略了可以编写托管本机代码,即.)因此,没有用户会遇到执行需要直接访问内存位置和指针的危险操作之一的应用程序.

实际上,.net CLR实现了一种编写本机代码的方法,可以通过.net"托管"代码调用.在这种情况下,本机代码作者的负担是不要犯任何指针和内存错误.

由于JVM和.net CLR都执行JIT编译,因此VM实际上是从提供的字节码创建本机编译的二进制文件.这个"JIT代码"比VM的解释器执行执行得更快,因为即使JIT生成的机器语言代码也包含VM将执行的所有VM所需的安全检查.因此,JIT输出代码不如通常不包含大量运行时检查的本机代码快.然而,这种速度性能缺陷被用于改进包括安全性在内的可靠性; 特别是,防止使用未初始化的存储,强制执行分配的类型安全,执行范围检查(因此防止基于堆栈和堆的缓冲区溢出),通过垃圾收集管理对象生存期,动态分配是类型安全的.执行此类运行时行为检查的环境正在实现虚拟机的规范,并且仅仅是虚拟机的机器语言实现.

  • 这是错的..Net语言被编译为IL,类似于java字节代码,它是分发给用户计算机执行的IL.区别在于,不是将字节码加载到VM中执行,而是在执行之前将.Net IL编译为本机代码.没有加载任何虚拟机. (11认同)
  • @Joel - 稍微澄清...... JITting是在方法级别,因此每个方法在第一次调用之前就被编译.从技术上讲,每次调用以前未调用的方法时,都会在程序执行期间调用JITter.JITter"关闭"的唯一时间是代码中的每个方法和类型都已被访问过一次. (3认同)
  • 乔尔:什么?当然,IL 是分发给用户然后 JIT 的,与 JVM 字节码相同。事实上,这就是我的观点——它在功能上(按设计)与 JVM 字节码相当。事实上,Sun Java 在 MS JVM、IIRC 之前就有 JIT。在 CLR 存在之前,两者都拥有它。还记得 MS JVM 吗? (3认同)
  • Joel的评论"与.Net相比,你的代码没有运行沙盒环境." 是完全错的. (3认同)
  • @Joel - 肯定是编译到本机代码是一个无关紧要的细节?具有快速解释器的CLR的未来版本可以改为解释,而且没有人需要知道这个事实...... (2认同)
  • 第一句话是错误的。IL 永远不会被解释,只会被编译。Java 也有 JIT,但这并没有改变 Java 是根据解释器指定的,而 .NET 是根据编译器指定的事实。 (2认同)

noc*_*ura 7

"虚拟机"部分指的是.NET代码被编译为EXE和DLL作为"中间"汇编语言(IL)以在虚拟机上运行,​​而不是真正的CPU汇编语言.然后,在运行时,ILM将转换为实际CPU程序集以供执行(称为实时,或JIT编译).

当然,您可以编写.NET编译器,以便将其编译为CPU汇编语言而不是IL.但是,这不能移植到所有CPU - 您必须为每个OS/CPU对编译不同的版本.但是通过编译成ILM,您可以让"虚拟机"处理CPU和操作系统特定的内容.

  • 我认为你的意思是IL,或更正确的CIL - 通用中间语言. (2认同)