当前位置:  开发笔记 > 编程语言 > 正文

Java的虚拟机和CLR

如何解决《Java的虚拟机和CLR》经验,为你挑选了4个好方法。

作为MSIL和Java字节码之间的差异问题的一种跟进?,Java虚拟机的工作方式(主要)差异或相似之处是什么?.NET Framework 公共语言运行时(CLR)有效吗?

还有,是 .NET框架 CLR是"虚拟机"还是没有虚拟机的属性?



1> benjismith..:

两种实现之间有很多相似之处(在我看来:是的,它们都是"虚拟机").

首先,它们都是基于堆栈的VM,没有"寄存器"的概念,就像我们习惯于在x86或PowerPC等现代CPU中看到的那样.所有表达式((1 + 1)/ 2)的评估是通过将操作数推入"堆栈"然后在指令(加,除等)需要消耗这些操作数时从堆栈中弹出这些操作数来执行的.每条指令将其结果推回堆栈.

这是实现虚拟机的一种便捷方式,因为世界上几乎每个CPU都有一个堆栈,但寄存器的数量通常不同(有些寄存器是专用的,每个指令都要求它的操作数在不同的寄存器中等等).

因此,如果您要为抽象机器建模,那么纯粹基于堆栈的模型是一种非常好的方法.

当然,真正的机器不能以这种方式运行.因此,JIT编译器负责执行字节码操作的"注册",实质上是调度实际的CPU寄存器以尽可能包含操作数和结果.

所以,我认为这是CLR和JVM之间最大的共性之一.

至于差异......

这两种实现之间的一个有趣的区别是CLR包含用于创建泛型类型的指令,然后用于将参数化特化应用于这些类型.因此,在运行时,CLR认为List 是与List 完全不同的类型.

在封面下,它对所有引用类型的特化使用相同的MSIL(因此List 使用与List 相同的实现,在API边界使用不同的类型转换),但每个值类型使用它自己的唯一实现(List 生成与List 完全不同的代码).

在Java中,泛型类型纯粹是一种编译器技巧.JVM没有关于哪些类具有类型参数的概念,并且它无法在运行时执行参数化特化.

从实际角度来看,这意味着您不能在泛型类型上重载Java方法.您不能使用具有相同名称的两种不同方法,区别在于它们是接受List 还是List .当然,由于CLR知道参数类型,因此在泛型类型特化上重载处理方法没有问题.

在日常的基础上,这是我在CLR和JVM之间最常见的区别.

其他重要的差异包括:

CLR有闭包(实现为C#代理).自Java 8以来,JVM仅支持闭包.

CLR具有协同程序(使用C#'yield'关键字实现).JVM没有.

CLR允许用户代码定义新的值类型(结构),而JVM提供固定的值类型集合(byte,short,int,long,float,double,char,boolean),并且只允许用户定义新的引用 - 类型(类).

CLR支持声明和操作指针.这一点特别有趣,因为JVM和CLR都采用严格的代压缩垃圾收集器实现作为其内存管理策略.在通常情况下,严格压缩GC的指针非常困难,因为当您将值从一个内存位置移动到另一个内存位置时,所有指针(和指针指针)都将变为无效.但是CLR提供了一种"固定"机制,以便开发人员可以声明一个代码块,在该代码块内不允许CLR移动某些指针.这很方便.

JVM中最大的代码单元是"包",可以通过'protected'关键字或可以说是JAR(即Java ARchive)来证明,这可以通过在类路径中指定jar并将其视为文件夹来证明代码 在CLR中,类被聚合到"程序集"中,CLR提供用于推理和操作程序集的逻辑(它们被加载到"AppDomains"中,为内存分配和代码执行提供子应用程序级沙箱).

CLR字节码格式(由MSIL指令和元数据组成)具有比JVM更少的指令类型.在JVM中,每个独特的操作(添加两个int值,添加两个浮点值等)都有自己独特的指令.在CLR中,所有MSIL指令都是多态的(添加两个值),JIT编译器负责确定操作数的类型并创建适当的机器代码.不过,我不知道哪个是优选策略.两者都有权衡.用于JVM的HotSpot JIT编译器可以使用更简单的代码生成机制(它不需要确定操作数类型,因为它们已经在指令中编码),但这意味着它需要更复杂的字节码格式,更多指令类型.

我已经使用Java(并欣赏JVM)已有十年了.

但是,在我看来,CLR现在几乎在所有方面都是优秀的实现.


闭包和生成器在语言级别实现,并简单地表示为CLR级别的类.
一个重要的区别是即时编译(CLR)与(Oracle/Sun)JVM中的自适应优化之间的对比.
他们如何处理堆的差异呢?CLR更依赖于OS /主机进程,而JVM或多或少地完全管理堆内存.

2> RoadWarrior..:

您的第一个问题是将JVM与.NET Framework进行比较 - 我假设您实际上打算与CLR进行比较.如果是这样,我想你可以写一本关于此的小书(编辑:看起来像Benji已经有了:-)

一个重要的区别是,与JVM不同,CLR被设计为与语言无关的架构.

另一个重要的区别是CLR专门设计用于实现与本机代码的高度互操作性.这意味着CLR必须在访问和修改本机内存时管理可靠性和安全性,并且还管理基于CLR的数据结构和本机数据结构之间的编组.

为了回答你的第二个问题,术语"虚拟机"是硬件世界中较早的术语(例如,IBM在20世纪60年代对360的虚拟化),这些术语过去是指底层机器的软件/硬件仿真,以实现相同的类型. VMWare的功能.

CLR通常被称为"执行引擎".在这种情况下,这是在x86之上的IL机器的实现.这也是JVM的作用,尽管你可以说CLR的多态字节码和JVM的类型字节码之间存在重要差异.

所以对你的第二个问题的迂腐回答是"不".但这实际上取决于你如何定义这两个术语.

编辑: JVM和CLR之间的另一个区别是JVM(版本6)非常不愿意将已分配的内存释放回操作系统,即使它可以.

例如,假设JVM进程最初启动并从操作系统分配25 MB内存.然后,应用程序代码尝试分配需要额外50 MB的分配.JVM将从操作系统分配额外的50 MB.一旦应用程序代码停止使用该内存,它就会被垃圾收集,并且JVM堆大小将减少.但是,JVM只会在某些特定情况下释放分配的操作系统内存.否则,对于剩余的进程生命周期,内存将保持分配状态.

另一方面,如果不再需要CLR,则将已分配的内存释放回操作系统.在上面的示例中,一旦堆减少,CLR就会释放内存.


JVM不会释放分配的内存是绝对不正确的。请参阅我对此问题的回答以获取证明:http://stackoverflow.com/questions/366658/java-6-excessive-memory-usage#367933

3> James Schek..:

可以从各种学术和私人来源找到关于差异的更多细节.CLR设计选择就是一个很好的例子.

一些具体的例子包括:

一些低级别的opperands被输入,例如"添加两个整数",其中CLR使用多态操作数.(即fadd/iadd/ladd vs just add)

目前,JVM进行更具侵略性的运行时分析和优化(即Hotspot).CLR目前进行JIT优化,但不进行运行时优化(即在运行时替换代码).

CLR没有内联虚拟方法,JVM确实......

支持CLR中的值类型,而不仅仅是"原语".



4> Allain Lalon..:

CLR和JVM都是虚拟机.

.NET Framework和Java运行时环境是各个VM及其库的捆绑.没有库,虚拟机就没用了.

推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有