Java 的虚拟机和 CLR
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/453610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java's Virtual Machine and CLR
提问by Frank V
As a sort of follow up to the question called Differences between MSIL and Java bytecode?, what is the (major) differences or similarity in how the Java Virtual Machine works versus how the .NET FrameworkCommon Language Runtime (CLR) works?
作为对名为MSIL 和 Java 字节码之间的差异的问题的一种跟进?,Java 虚拟机的工作方式与 Java 虚拟机的工作方式之间的(主要)差异或相似之处是什么?.NET 框架公共语言运行时 (CLR) 有效吗?
Also, is the .NET frameworkCLR a "virtual machine" or does it not have the attributes of a virtual machine?
另外,是 .NET 框架CLR是“虚拟机”还是不具备虚拟机的属性?
采纳答案by benjismith
There are a lot of similarities between both implementations (and in my opinion: yes, they're both "virtual machines").
两种实现之间有很多相似之处(在我看来:是的,它们都是“虚拟机”)。
For one thing, they're both stack-based VM's, with no notion of "registers" like we're used to seeing in a modern CPU like the x86 or PowerPC. The evaluation of all expressions ((1 + 1) / 2) is performed by pushing operands onto the "stack" and then popping those operands off the stack whenever an instruction (add, divide, etc) needs to consume those operands. Each instruction pushes its results back onto the stack.
一方面,它们都是基于堆栈的 VM,没有像 x86 或 PowerPC 这样的现代 CPU 中常见的“寄存器”概念。所有表达式 ((1 + 1) / 2) 的计算都是通过将操作数推入“堆栈”,然后在指令(加法、除法等)需要使用这些操作数时将这些操作数从堆栈中弹出来执行的。每条指令将其结果压回到堆栈上。
It's a convenient way to implement a virtual machine, because pretty much every CPU in the world has a stack, but the number of registers is often different (and some registers are special-purpose, and each instruction expects its operands in different registers, etc).
这是一种实现虚拟机的便捷方式,因为世界上几乎每个 CPU 都有一个堆栈,但是寄存器的数量通常是不同的(有些寄存器是专用的,每条指令都期望它的操作数在不同的寄存器中,等等)。
So, if you're going to model an abstract machine, a purely stack-based model is a pretty good way to go.
因此,如果您要对抽象机器进行建模,那么纯基于堆栈的模型是一个不错的选择。
Of course, real machines don't operate that way. So the JIT compiler is responsible for performing "enregistration" of bytecode operations, essentially scheduling the actual CPU registers to contain operands and results whenever possible.
当然,真正的机器不会那样操作。因此,JIT 编译器负责执行字节码操作的“注册”,实质上是调度实际的 CPU 寄存器以尽可能包含操作数和结果。
So, I think that's one of the biggest commonalities between the CLR and the JVM.
所以,我认为这是 CLR 和 JVM 之间最大的共同点之一。
As for differences...
至于差异...
One interesting difference between the two implementations is that the CLR includes instructions for creating generic types, and then for applying parametric specializations to those types. So, at runtime, the CLR considers a List<int> to be a completely different type from a List<String>.
两种实现之间一个有趣的区别是,CLR 包含用于创建泛型类型的指令,然后用于将参数特化应用于这些类型。因此,在运行时,CLR 将 List<int> 视为与 List<String> 完全不同的类型。
Under the covers, it uses the same MSIL for all reference-type specializations (so a List<String> uses the same implementation as a List<Object>, with different type-casts at the API boundaries), but each value-type uses its own unique implementation (List<int> generates completely different code from List<double>).
在幕后,它对所有引用类型特化使用相同的 MSIL(因此 List<String> 使用与 List<Object> 相同的实现,在 API 边界具有不同的类型转换),但每个值类型使用它自己独特的实现(List<int> 生成与 List<double> 完全不同的代码)。
In Java, generic types are a purely a compiler trick. The JVM has no notion of which classes have type-arguments, and it's unable to perform parametric specializations at runtime.
在 Java 中,泛型类型纯粹是一种编译器技巧。JVM 不知道哪些类具有类型参数,并且无法在运行时执行参数化特化。
From a practical perspective, that means you can't overload Java methods on generic types. You can't have two different methods, with the same name, differing only on whether they accept a List<String> or a List<Date>. Of course, since the CLR knows about parametric types, it has no problem handling methods overloaded on generic type specializations.
从实际的角度来看,这意味着您不能在泛型类型上重载 Java 方法。不能有两个名称相同的不同方法,其区别仅在于它们接受 List<String> 还是 List<Date>。当然,由于 CLR 知道参数类型,因此处理泛型类型特化上的重载方法没有问题。
On a day-to-day basis, that's the difference that I notice most between the CLR and the JVM.
在日常工作中,这是我最注意到 CLR 和 JVM 之间的差异。
Other important differences include:
其他重要的区别包括:
The CLR has closures (implemented as C# delegates). The JVM does support closures only since Java 8.
The CLR has coroutines (implemented with the C# 'yield' keyword). The JVM does not.
The CLR allows user code to define new value types (structs), whereas the JVM provides a fixed collection of value types (byte, short, int, long, float, double, char, boolean) and only allows users to define new reference-types (classes).
The CLR provides support for declaring and manipulating pointers. This is especially interesting because both the JVM and the CLR employ strict generational compacting garbage collector implementations as their memory-management strategy. Under ordinary circumstances, a strict compacting GC has a really hard time with pointers, because when you move a value from one memory location to another, all of the pointers (and pointers to pointers) become invalid. But the CLR provides a "pinning" mechanism so that developers can declare a block of code within which the CLR is not allowed to move certain pointers. It's very convenient.
The largest unit of code in the JVM is either a 'package' as evidenced by the 'protected' keyword or arguably a JAR (i.e. Java ARchive) as evidenced by being able to specifiy a jar in the classpath and have it treated like a folder of code. In the CLR, classes are aggregated into 'assemblies', and the CLR provides logic for reasoning about and manipulating assemblies (which are loaded into "AppDomains", providing sub-application-level sandboxes for memory allocation and code execution).
The CLR bytecode format (composed of MSIL instructions and metadata) has fewer instruction types than the JVM. In the JVM, every unique operation (add two int values, add two float values, etc) has its own unique instruction. In the CLR, all of the MSIL instructions are polymorphic (add two values) and the JIT compiler is responsible for determining the types of the operands and creating appropriate machine code. I don't know which is the preferably strategy, though. Both have trade-offs. The HotSpot JIT compiler, for the JVM, can use a simpler code-generation mechanism (it doesn't need to determine operand types, because they're already encoded in the instruction), but that means it needs a more complex bytecode format, with more instruction types.
CLR 有闭包(实现为 C# 委托)。JVM 仅从 Java 8 开始才支持闭包。
CLR 具有协程(使用 C# 'yield' 关键字实现)。JVM 没有。
CLR 允许用户代码定义新的值类型(结构),而 JVM 提供固定的值类型集合(byte、short、int、long、float、double、char、boolean)并且只允许用户定义新的引用——类型(类)。
CLR 支持声明和操作指针。这一点特别有趣,因为 JVM 和 CLR 都采用严格的分代压缩垃圾收集器实现作为它们的内存管理策略。在一般情况下,严格压缩 GC 很难处理指针,因为当你将一个值从一个内存位置移动到另一个内存位置时,所有的指针(以及指向指针的指针)都会变得无效。但是 CLR 提供了一种“固定”机制,以便开发人员可以声明一个代码块,在该代码块中 CLR 不允许移动某些指针。这很方便。
JVM 中最大的代码单元是“包”,如“protected”关键字所证明的那样,或者可以说是 JAR(即 Java 归档),如能够在类路径中指定 jar 并将其视为文件夹所证明的那样的代码。在 CLR 中,类被聚合到“程序集”中,CLR 提供推理和操作程序集的逻辑(它们被加载到“AppDomains”中,为内存分配和代码执行提供子应用程序级沙箱)。
CLR 字节码格式(由 MSIL 指令和元数据组成)的指令类型比 JVM 少。在 JVM 中,每个唯一的操作(添加两个 int 值,添加两个浮点值等)都有自己唯一的指令。在 CLR 中,所有 MSIL 指令都是多态的(添加两个值),JIT 编译器负责确定操作数的类型并创建适当的机器代码。不过,我不知道哪个是最好的策略。两者都有取舍。HotSpot JIT 编译器,对于 JVM,可以使用更简单的代码生成机制(它不需要确定操作数类型,因为它们已经在指令中编码),但这意味着它需要更复杂的字节码格式,具有更多指令类型。
I've been using Java (and admiring the JVM) for about ten years now.
我已经使用 Java(并欣赏 JVM)大约十年了。
But, in my opinion, the CLR is now the superior implementation, in almost every way.
但是,在我看来,CLR 现在几乎在所有方面都是卓越的实现。
回答by Allain Lalonde
The CLR and the JVM are both virtual machines.
CLR 和 JVM 都是虚拟机。
The .NET Framework and the Java Runtime Environment are the bundling of the respective VMs and their libraries. Without libraries the VMs are pretty useless.
.NET Framework 和 Java 运行时环境捆绑了相应的 VM 及其库。没有库,VM 就毫无用处。
回答by Diones
It is not a virtual machine, the .net framework compiles the assemblies into native binary at the time of the first run:
它不是虚拟机,.net 框架在第一次运行时将程序集编译为本机二进制文件:
In computing, just-in-time compilation (JIT), also known as dynamic translation, is a technique for improving the runtime performance of a computer program. JIT builds upon two earlier ideas in run-time environments: bytecode compilation and dynamic compilation. It converts code at runtime prior to executing it natively, for example bytecode into native machine code. The performance improvement over interpreters originates from caching the results of translating blocks of code, and not simply reevaluating each line or operand each time it is met (see Interpreted language). It also has advantages over statically compiling the code at development time, as it can recompile the code if this is found to be advantageous, and may be able to enforce security guarantees. Thus JIT can combine some of the advantages of interpretation and static (ahead-of-time) compilation.
在计算中,即时编译 (JIT),也称为动态翻译,是一种提高计算机程序运行时性能的技术。JIT 建立在运行时环境中的两个早期思想之上:字节码编译和动态编译。它在本地执行之前在运行时将代码转换为本地机器代码,例如字节码。对解释器的性能改进源于缓存翻译代码块的结果,而不是在每次遇到时简单地重新评估每一行或操作数(请参阅解释语言)。与在开发时静态编译代码相比,它还具有优势,因为如果发现这样做有利,它可以重新编译代码,并且可能能够强制执行安全保证。
Several modern runtime environments, such as Microsoft's .NET Framework, most implementations of Java, and most recently Actionscript 3, rely on JIT compilation for high-speed code execution.
一些现代运行时环境,例如 Microsoft 的 .NET Framework、大多数 Java 实现以及最近的 Actionscript 3,都依赖 JIT 编译来实现高速代码执行。
Source: http://en.wikipedia.org/wiki/Just-in-time_compilation
来源:http: //en.wikipedia.org/wiki/Just-in-time_compilation
Adding up .NET framework contains a virtual machine, just like Java.
添加.NET框架包含一个虚拟机,就像Java一样。
回答by HTTP 410
Your first question is comparing the JVM with the .NET Framework - I assume you actually meant to compare with the CLR instead. If so, I think you could write a small book on this (EDIT:looks like Benji already has :-)
您的第一个问题是将 JVM 与 .NET Framework 进行比较 - 我假设您实际上打算与 CLR 进行比较。如果是这样,我想你可以写一本关于这个的小书(编辑:看起来 Benji 已经有了 :-)
One important difference is that the CLR is designed to be a language-neutral architecture, unlike the JVM.
一个重要的区别是,与 JVM 不同,CLR 被设计为一种与语言无关的架构。
Another important difference is that the CLR was specifically designed to allow for a high level of interoperability with native code. This means that the CLR must manage reliability and security when native memory is accessed and modified, and also manage marshallingbetween CLR-based data structures and native data structures.
另一个重要的区别是 CLR 专门设计为允许与本机代码的高级互操作性。这意味着 CLR 必须在访问和修改本机内存时管理可靠性和安全性,还必须管理基于 CLR 的数据结构和本机数据结构之间的编组。
To answer your second question, the term “virtual machine” is an older term from the hardware world (e.g. IBM's virtualisation of the 360 in the 1960s) that used to mean a software/hardware emulation of the underlying machine to accomplish the same sort of stuff that VMWare does.
要回答您的第二个问题,“虚拟机”一词是硬件世界中的一个旧术语(例如,IBM 在 1960 年代对 360 进行虚拟化),它曾经表示底层机器的软件/硬件仿真以完成相同类型的VMWare 所做的事情。
The CLR is often referred to as an "execution engine". In this context, that's an implementation of an IL Machine on top of an x86. This is also what the JVM does, although you can argue that there's an important difference between the CLR's polymorphic bytecodes and the JVM's typed bytecodes.
CLR 通常被称为“执行引擎”。在这种情况下,这是在 x86 之上的 IL 机器的实现。这也是 JVM 所做的,尽管您可能会争辩说 CLR 的多态字节码和 JVM 的类型化字节码之间存在重要区别。
So the pedantic answer to your second question is "no". But it really comes down to to how you define these two terms.
所以对你的第二个问题的迂腐回答是“不”。但这实际上取决于您如何定义这两个术语。
EDIT:One more difference between the JVM and the CLR is that the JVM (version 6) is very reluctantto release allocated memory back to the operating system, even where it can.
编辑:JVM 和 CLR 之间的另一个区别是 JVM(版本 6)非常不愿意将分配的内存释放回操作系统,即使它可以。
For example, let's say that a JVM process starts and allocates 25 MB of memory from the operating system initially. The app code then attempts allocations that require an additional 50 MB. The JVM will allocate an additional 50 MB from the operating system. Once the application code has stopped using that memory, it is garbage-collected and the JVM heap size will decrease. However, the JVM will only free the allocated operating system memory under certain very specific circumstances. Otherwise, for the rest of the process lifetime that memory will remain allocated.
例如,假设 JVM 进程启动并最初从操作系统分配 25 MB 内存。然后,应用程序代码尝试分配需要额外 50 MB 的空间。JVM 将从操作系统中额外分配 50 MB。一旦应用程序代码停止使用该内存,它就会被垃圾收集并且 JVM 堆大小将减小。但是,JVM 只会在某些非常特定的情况下释放分配的操作系统内存。否则,在剩余的进程生命周期中,该内存将保持分配状态。
The CLR, on the other hand, releases allocated memory back to the operating system if it's no longer needed. In the example above, the CLR would have released the memory once the heap had decreased.
另一方面,如果不再需要,CLR 会将分配的内存释放回操作系统。在上面的示例中,一旦堆减少,CLR 就会释放内存。
回答by James Schek
More specifics on the differences can be found at from various academic and private sources. Once good example is CLR Design Choices.
可以从各种学术和私人资源中找到有关差异的更多细节。一个很好的例子是CLR 设计选择。
Some specific examples include:
一些具体的例子包括:
- Some low-level opperands are typed such as "add two ints" where as CLR uses a polymorphic operand. (i.e. fadd/iadd/ladd vs just add)
- Currently, the JVM does more aggresive runtime profiling and optimization (i.e. Hotspot). CLR currently does JIT optimizations, but not runtime optimization (i.e. replace code while you're running).
- CLR doesn't inline virtual methods, JVM does...
- Support for value types in the CLR beyond just the "primitives".
- 一些低级操作数是类型化的,例如“添加两个整数”,而 CLR 使用多态操作数。(即 fadd/iadd/ladd 与仅添加)
- 目前,JVM 执行更积极的运行时分析和优化(即 Hotspot)。CLR 当前进行 JIT 优化,但不进行运行时优化(即在您运行时替换代码)。
- CLR 不内联虚拟方法,JVM 会...
- 支持 CLR 中的值类型,而不仅仅是“原语”。