jit 方法内联
即时(JIT)
即时(JIT)编译器是Java虚拟机的大脑。 JVM中对JIT编译器的影响最大。
一会儿,让我们退后一步,看看已编译和未编译语言的示例。
诸如Go,C和C ++之类的语言之所以称为编译语言,是因为它们的程序以二进制(编译)代码的形式分发,该代码针对特定的CPU。
另一方面, 解释语言如PHP和Perl。 只要机器具有解释器,就可以在任何CPU上运行相同的程序源代码。 解释器在执行该行时将程序的每一行转换为二进制代码。
Java试图在这里找到中间立场。 Java应用程序已编译,但没有被编译为特定CPU的特定二进制文件,而是被编译为bytecode 。 这为Java提供了与解释语言无关的平台。 但是Java不止于此。
在典型的程序中,只有一小部分代码会频繁执行,而应用程序的性能主要取决于这些代码部分的执行速度。 这些关键部分被称为应用程序的热点 。
JVM执行特定代码段的次数越多,有关它的信息就越多。 这使JVM可以做出明智/优化的决策,并将小的热代码编译为CPU特定的二进制文件。 该过程称为即时编译(JIT) 。
现在,我们运行一个小程序,观察JIT编译。
public class App {public static void main(String[] args) {long sumOfEvens = 0;for(int i = 0; i < 100000; i++) {if(isEven(i)) {sumOfEvens += i;}}System.out.println(sumOfEvens);}public static boolean isEven(int number) {return number % 2 == 0;}
}#### Run
javac App.java && \
java -server \-XX:-TieredCompilation \-XX:+PrintCompilation \- XX:CompileThreshold=100000 App#### Output
87 1 App::isEven (16 bytes)
2499950000
输出告诉我们isEven方法已编译。 我故意禁用了TieredCompilation,以仅获取最常编译的代码。
JIT编译的代码将大大提高您的应用程序的性能。 要检查吗? 编写一个简单的基准代码。
内联
内联是JIT编译器进行的最重要的优化之一。 内联将方法调用替换为方法的主体,以避免方法调用的开销。
让我们再次运行相同的程序,这次观察内联。
#### Run
javac App.java && \
java -server \-XX:+UnlockDiagnosticVMOptions \-XX:+PrintInlining \-XX:-TieredCompilation App#### Output
@ 12 App::isEven (16 bytes) inline (hot)
2499950000
再次内联将大大提高您的应用程序的性能。
转义分析
转义分析是一种技术,通过该技术,JIT编译器可以分析新对象的使用范围,并决定将其分配在Java堆还是方法堆栈上。 它还消除了对所有非全局转义对象的锁定
让我们运行一个小程序,观察垃圾回收。
public class App {public static void main(String[] args) {long sumOfArea = 0;for(int i = 0; i < 10000000; i++) {Rectangle rect = new Rectangle(i+5, i+10);sumOfArea += rect.getArea();}System.out.println(sumOfArea);}static class Rectangle {private int height;private int width;public Rectangle(int height, int width) {this.height = height;this.width = width;}public int getArea() {return height * width;}}
}
在此示例中,矩形对象被创建并且仅在循环内可用,它们的特征是NoEscape,它们将分配在堆栈上而不是堆上。 具体来说,这意味着将不会发生垃圾回收。
让我们在没有EscapeAnalysis的情况下运行程序。
#### Run
javac App.java && \
java -server \-verbose:gc \-XX:-DoEscapeAnalysis App#### Output
[GC (Allocation Failure) 65536K->472K(251392K), 0.0007449 secs]
[GC (Allocation Failure) 66008K->440K(251392K), 0.0008727 secs]
[GC (Allocation Failure) 65976K->424K(251392K), 0.0005484 secs]
16818403770368
如您所见,GC已启动。 分配失败意味着年轻一代中没有剩余空间来分配对象。 因此,这是年轻GC的正常原因。
这次让我们使用EscapeAnalysis运行它。
#### Run
javac App.java && \
java -server \-verbose:gc \-XX:+DoEscapeAnalysis App#### Output
16818403770368
这次没有发生GC。 从根本上讲,这意味着创建寿命短且作用域狭窄的对象不一定会引入垃圾。
默认情况下, DoEscapeAnalysis选项处于启用状态。 请注意,只有Java HotSpot Server VM支持此选项。
因此,我们所有人都应该避免过早的优化,而应专注于编写更具可读性/可维护性的代码,并让JVM来完成它的工作。
翻译自: https://www.javacodegeeks.com/2015/12/jit-compiler-inlining-escape-analysis.html
jit 方法内联