jvm与jit编译器的区别
Hello people!!
大家好!!
I can see that the Java community is growing a lot but there are a lot of Java developers only focused on Spring, microservices, and other fancy tools, and forgetting to understand how the incredible Java Virtual Machine works.
我可以看到Java社区正在增长,但是有很多Java开发人员只专注于Spring,微服务和其他高级工具,却忘了理解令人难以置信的Java虚拟机如何工作。
I can understand that, using Spring Boot in a microservices architecture, will be rare the case where we need to tune the performance of an application (since we have a microservice / micro-application and Spring Boot brings to us the Development by Convention) based on a JVM investigation.
我可以理解,在微服务架构中使用Spring Boot的情况很少见,因为我们需要调整应用程序的性能(因为我们拥有微服务/微应用程序,并且Spring Boot为我们带来了Convention by Convention )。在JVM调查中。
But I’m the type of person that really wants to know how things work behind the hood, and I think this knowledge is important to create better and performative code.
但是我是那种真正想知道事物在幕后如何工作的人,我认为这些知识对于创建更好的性能代码很重要。
And as my mother always told me: It is better to know and not need than need and not know.
就像我妈妈一直告诉我的那样:知道而不是需要总比需要和不知道好。
So, let’s start talking about how JVM runs the Java code.
因此,让我们开始讨论JVM如何运行Java代码。
The Java compiler (javac) will compile your .java class into a .class file. This .class is your bytecode.
Java编译器( javac )将您的.java类编译为.class文件。 该.class是您的字节码 。
This bytecode (.class files) can be packaged into a JAR file or a WAR file. When we are running our app using the java command, the Java Virtual Machine (JVM) will run our bytecode, that is, our .class files.
该字节码(.class文件)可以打包为JAR文件或WAR文件。 当我们使用java命令运行应用程序时, Java虚拟机(JVM)将运行我们的字节码,即.class文件。
This capability to an interpreter at runtime the bytecode is how Java can achieve one of its benefits, WORA (Write Once, Run Anywhere). But the key part is not only run anywhere but run anywhere with consistent results!
字节码在运行时对解释器的这种能力是Java如何实现其优势之一,即WORA(一次写入,可在任何地方运行)。 但是关键部分不仅可以在任何地方运行,而且可以在任何地方运行并获得一致的结果!
So, that’s why Java became so famous because, with this WORA concept allowed by the JVM, we now could run any Java apps on Mac, Windows, Linux, or any other Operation System (OS) for which a JVM exists.
因此,这就是Java如此出名的原因,因为有了JVM允许的WORA概念,我们现在可以在Mac,Windows,Linux或存在JVM的任何其他操作系统(OS)上运行任何Java应用程序。
So, the flow is: Java code is going to be compiled into bytecode (.class files) and the JVM can interpret this bytecode.
因此,流程为:Java代码将被编译为字节码(.class文件),并且JVM可以解释该字节码。
But you are wondering yourself right now, why do we still need a JVM if nowadays we have Docker?
但是您现在想知道自己, 如果现在有了Docker , 为什么我们仍然需要JVM ?
And the answer is simple: Because this is only one of the huge amount of features that the JVM contains and also because JVM has complex algorithms to make it more efficient than a traditional code interpreter would be.
而答案很简单:因为这是唯一的功能,在JVM中包含大量的之一 ,也是因为JVM有复杂的算法,使其更有效地比传统的代码解释会。
For example, if you are writing code in a non compiled (that is, a runtime interpreted) language like PHP using an interpreter, each line of PHP code is only looked at, analyzed and the way to execute it is determined as it is needed. In a JVM it’s a much more complicated process.
例如,如果您使用解释器以非编译(即运行时解释)语言(如PHP)编写代码,则仅查看,分析每行PHP代码,并根据需要确定执行方式。 在JVM中,这是一个非常复杂的过程。
So, the first benefit of using the Java Virtual Machine (JVM) is because the JVM will not run the Java code directly, but rather the Java bytecode and in fact, any language which can be compiled to a JVM compatible bytecode can be run on the JVM like Scala, Groovy, Kotlin, Clojure, etc.
因此,使用Java虚拟机(JVM)的第一个好处是因为JVM不会直接运行Java代码,而是直接运行Java字节码,实际上,任何可以编译为JVM兼容字节码的语言都可以在其上运行像Scala,Groovy,Kotlin,Clojure等JVM。
But Julio, you said that a JVM uses a much more complicated process, how is this process?
但是Julio,您说过JVM使用的过程要复杂得多,这个过程怎么样?
Amazing question!
令人惊讶的问题!
Initially, JVM acts like any other interpreter, running each line of code as it is needed (like the PHP Interpreter that we mentioned before). However, by default, this would make the code execution a little bit slow, so, certainly, if you compare this code written in a language like C, which will be compiled to native machine code, the way that this kind of language works is that the code is compiled into a runnable format that the OS can comprehend directly, it means that the OS doesn’t need any additional software to interpret or run it.
最初,JVM的行为就像其他解释器一样,根据需要运行每一行代码(例如我们前面提到PHP Interpreter)。 但是,默认情况下,这会使代码的执行速度变慢,因此,当然,如果您比较用C之类的语言编写的代码,它将被编译为本机代码,则这种语言的工作方式是代码被编译为OS可以直接理解的可运行格式,这意味着OS不需要任何其他软件即可解释或运行它。
This makes it quick to run compared to interpreted languages but using this kind of language, that is compiled natively means that we lose the WORA property.
与解释语言相比,它可以更快地运行,但是使用这种语言,即本地编译意味着我们失去了WORA属性。
So, how does JVM help us with this problem, the slower execution in interpreted languages than compiled languages?
那么,JVM如何帮助我们解决这个问题,即解释型语言比编译型语言的执行速度慢?
That’s why Java HostSpot VM has a feature called JIT (Just In Time) Compilation!
这就是Java HostSpot VM具有称为JIT(即时)编译功能的原因!
The JVM will monitor which blocks of code are run the most often, which methods or parts of methods, specifically loops are executed the most frequently, and then the JVM can decide for example, that a particular method is being used a lot so, the code execution would be speeded up if that method was compiled to native machine code and it this is exactly what JVM will do.
JVM将监视哪些代码块运行最频繁,哪些方法或方法的一部分,特别是循环最频繁地执行,然后JVM可以确定例如某个特定方法被大量使用,如果将该方法编译为本机代码 ,则代码执行速度将得到提高,而这正是JVM的工作方式。
At some point, our application is being run in interpretive mode, as bytecode, and some it is no longer bytecode but it is running as compiled native machine code.
在某些时候,我们的应用程序以字节码的形式在解释性模式下运行,而有些不再是字节码的,而是作为已编译的本机代码运行。
With this, the part of the code that was compiled to native machine code will run faster than the bytecode interpreted part.
这样,编译为本地机器代码的代码部分将比字节码解释的部分运行得更快。
Just to be clear: When we are talking about “native machine code” we are talking about an executable code that can be understood directly by your Operating System. It means that if you are running your app in a Windows JVM will generate a specific code that can be natively understood by the Windows OS, but if you now are running in Linux, this generated native machine code will be different.
明确一点:当我们谈论“本地机器代码”时,我们所谈论的是可以由您的操作系统直接理解的可执行代码。 这意味着,如果您在Windows JVM上运行您的应用程序,则会生成Windows操作系统可以原生理解的特定代码,但是如果您现在在Linux上运行,则生成的本机代码将有所不同。
So, the Windows JVM can create a native Windows code and the Linux JVM can create a native Linux code, for example.
因此,例如,Windows JVM可以创建本机Windows代码,而Linux JVM可以创建本机Linux代码。
This process of native combination is completely transparent to us and that’s why sometimes people think that they don’t need to know about it, but it has an important implication.
本机组合的过程对我们完全透明,这就是为什么有时人们认为他们不需要了解它的原因,但是它具有重要的意义。
Your code will run faster the longer it is left to run.
您的代码可以运行的时间越长,运行速度就越快。
That’s because the JVM can profile your code and work out which bits of it could be optimized by compiling them to native machine code.
这是因为JVM可以对您的代码进行概要分析,并确定可以通过将其编译为本地机器代码来优化代码的哪些位。
So, a method that runs multiple times every minute is very likely to be Just In Time compiled quickly, but a method that might run once a day might not ever be JIT compiled.
因此,每分钟运行多次的方法很可能会快速地按时编译,但是每天运行一次的方法可能永远不会JIT编译。
Important note: The process of compiling the bytecode to native machine code will run in a separate thread. The JVM is, of course, a multi-threaded application itself, so the threads within the JVM responsible for running the code that is interpreting the bytecode and executing the bytecode won’t be affected by the thread doing JIT compiling. It means that the JIT compiling process doesn’t stop the application running.
重要说明:将字节码编译为本机代码的过程将在单独的线程中运行。 JVM当然是一个多线程应用程序,因此JVM中负责运行解释字节码并执行字节码的代码的线程不会受到执行JIT编译的线程的影响。 这意味着JIT编译过程不会停止应用程序的运行。
While the compilation is taking place, the JVM will continue to use the interpreted version but once that compilation is complete and the native machine code version is available, then the JVM will seamlessly switch to use the JIT-compiled version instead of the bytecode. This process is called on-stack replacement (OSR) and I’ll explain better more forward.
在进行编译时,JVM将继续使用解释版本,但是一旦编译完成并且本机代码版本可用,那么JVM将无缝切换为使用JIT编译版本而不是字节码。 这个过程称为栈上替换 ( OSR ),我将在以后做更好的解释。
But there is a case that you might need to look closer to check if the JIT Compilation process is decreasing your application performance.
但是在某些情况下,您可能需要仔细检查JIT编译过程是否正在降低您的应用程序性能。
If your application is using all of the available CPU resources, you can potentially see a temporary reduction in performance if JIT compilation is running, although it would only be in the most critical and high power processing application that you might notice this, and even then, it will be worth taking a slight drop in processing power to get the benefit of the native code version for your method.
如果您的应用程序正在使用所有可用的CPU资源,则即使正在运行JIT编译,您也可能会看到性能的暂时下降,尽管它只会出现在您可能会注意到的最关键,最强大的处理应用程序中,即使这样,在处理能力上略有下降,以获取方法的本机代码版本是值得的。
Important note: If you want to measure the performance of two different methods (with different implementations) and determine how long the methods will take to run, you definitely will get different results when your application first starts and when your application has been running for a short while. You need to think about whether you’re assessing the performance of the code before it has been natively compiled or after. To do that you can use JMH (Java Microbenchmark Harness) and use the warmups configuration to handle this. Here you can find a great example of how to use JHM.
重要说明:如果您要衡量两种不同方法(具有不同实现)的性能并确定这些方法将花费多长时间,则在您的应用程序首次启动以及应用程序运行了一段时间后,您肯定会获得不同的结果。一会儿。 您需要考虑是在本地编译之前还是之后评估代码的性能。 为此,您可以使用JMH(Java Microbenchmark线束)并使用warmups配置进行处理。 在这里,您可以找到有关如何使用JHM的绝佳示例。
So, any method or code block can be compiled into native machine code.
因此, 任何方法或代码块都可以编译为本机代码。
To summarize, the JVM has 2 different compilers. The javac and JIT Compiler.
总而言之,JVM有2个不同的编译器。 javac和JIT编译器。
The javac is responsible for compiling Java code for bytecode.
javac负责为字节码编译Java代码。
The JIT (Just in Time) Compiler is composed of 2 “sub-compilers”, the C1 (Client Compiler) and C2 (Server Compiler).
JIT(即时)编译器由2个“子编译器”组成,它们分别是C1(客户端编译器)和C2(服务器编译器)。
The C1 will take the bytecode (already compiled by javac) and optimize this code by profiling (basically enriching the Java code metadata according to the number of executions) in 3 layers and when realizing that this is a very used code based on the information contained in profiling, C2 will compile this code for Native code and then place it in CodeCache.
C1将采用字节码(已经由javac编译)并通过在3层中进行概要分析(基本上根据执行次数来丰富Java代码元数据)来优化该代码,并在基于包含的信息意识到这是一个非常有用的代码时在概要分析中,C2将为本地代码编译此代码,然后将其放置在CodeCache中。
Now that you already understood how the JVM executes your Java Code and the benefits and drawbacks in this process, in the next parts of this series I’ll explain how can we track and see the JIT compilation.
既然您已经了解了JVM如何执行Java代码以及此过程中的利弊,那么在本系列的下一部分中,我将说明如何跟踪和查看JIT编译。
Hope you liked it, see you!
希望你喜欢它,再见!
翻译自: https://medium.com/@julio.falbo/understand-jvm-and-jit-compiler-part-1-a94c27d32478
jvm与jit编译器的区别