Depth understanding of JVM virtual machine 8: Java compiler and runtime optimization Optimization

java compiler optimization

Micro-channel public number of rivers and lakes] [Java technology Java, a technical engineer Ali station. Author Huang oblique, focused Java related technologies: SSM, SpringBoot, MySQL, distributed, middleware, cluster, Linux, network, multi-threaded, occasionally speaking point Docker, ELK, as well as dry goods and technology to share the learning experience, committed to Java full stack development! (No reply after public concern "Java" Java can receive basic, advanced, and the project architect and other free learning materials, more databases, distributed, service and other popular micro learning video technology, rich content, both theory and practice, also presented will be the original author of the study guide Java, Java programmer interview guide and other dry goods resources)

 

                     9eedaaa588bef997bef63a7160fa349134bdb78c

compile java language actually during the operation period of uncertainty, because it can be divided into three categories compilation process:
1. Compile the front: the .java file into a .class file
2. The back-end compiler: bytecode into machine code
3. statically compiled ahead: * .java files directly compiled to native machine code
from JDK1.3 start the virtual machine is designed to optimize the performance of the team took to the centralized back-end-time compilation, so you can make those not by Javac Class files (such as JRuby, Groovy and other languages Class file) generated by the compiler optimization can also enjoy the benefits of
Java compiler at run-time optimization process is more important for real-time running, the front-end and compile at optimization of the process for compiling program code for closer relations    

Early (compile-time) optimization

早期编译过程主要分为3个部分:
1.解析与填充符号表过程:词法、语法分析;填充符号表  
2.插入式注解处理器的注解处理过程  
3.语义分析与字节码生成过程:标注检查、数据与控制流分析、解语法糖、字节码生成
Generics and type erasure

Generic Java language program source exists only in the compiled byte code file, the original has been replaced by the original type, and casts the code inserted at the appropriate place

泛型擦除前的例子    
public static void main( String[] args ) { Map<String,String> map = new HashMap<String, String>(); map.put("hello","你好"); System.out.println(map.get("hello")); } 泛型擦除后的例子 public static void main( String[] args ) { Map map = new HashMap(); map.put("hello","你好"); System.out.println((String)map.get("hello")); }
Automatic packing, unpacking and through the loop

Automatic packing, unpacking after compilation will be converted to the corresponding packaging and reduction method, such as Integer.valueOf () and Integer.intValue (), but put the code back through the loop iterator become implemented, vararg It will become array type parameters.
However, the wrapper class "==" not automatically unpacking operation without experiencing arithmetic operations, and their equals () method does not handle data transformation relationship.

Conditional compilation

Java language can also be conditional compilation method is to use a constant condition of the if statement, it will be "run" at compile time:

public static void main(String[] args) { if(true){ System.out.println("block 1"); } else{ System.out.println("block 2"); } } 编译后Class文件的反编译结果: public static void main(String[] args) { System.out.println("block 1"); }

Only condition is a constant if statement, which is syntactic sugar Java language, according to the true and false Boolean constant values, branch does not hold the compiler will eliminate blocks of code

Late (run-time) optimization

Interpreter and compiler

Java program is initially interpreted by an interpreter, when the program needs to quickly launch and execution, the interpreter can first play, eliminating the need for time to compile, execute immediately; when the program is run, over time, gradually compile play a role in bringing more and more code is compiled to native code, to achieve higher efficiency. Interpreted save memory, compiler implementation to enhance efficiency.  At the same time, the interpreter can be used as a radical when compiler optimization "escape hatch" so the compiler based on the probability of choosing some of the most of the time can enhance the speed of optimization methods, optimization when the radical assumption does not hold, then return to the de-optimized by explain the state to continue.

HotSpot virtual machine built into the two-time compiler, called Client Compiler (C1 compiler) and Server Compiler (C2 compiler), the default way in which the use of an interpreter and a compiler directly with the work, which compiler depending on virtual machine running mode, you can also specify themselves. If forced the virtual machine is running and "interpreted mode", the compiler totally involved in the work, if forced to virtual machines running in the "compilation mode", the precedence compilation mode execution program, the interpreter still be involved in the implementation in the case of compilation can not be carried out process.

Layered compilation strategy
分层编译策略作为默认编译策略在JDK1.7的Server模式虚拟机中被开启,其中包括:
第0层:程序解释执行,解释器不开启性能监控功能,可触发第1层编译;
第1层:C1编译,将字节码编译成本地代码,进行简单可靠的优化,如有必要将加入性能监控的逻辑;
第2层:C2编译,也是将字节码编译成本地代码,但是会启动一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。 实施分层编译后,C1和C2将会同时工作,C1获取更高的编译速度,C2获取更好的编译质量,在解释执行的时候也无须再承担性能监控信息的任务。 
Hot Code probe
在运行过程中会被即时编译器编译的“热点代码”有两类:
1.被多次调用的方法:由方法调用触发的编译,属于JIT编译方式
2.被多次执行的循环体:也以整个方法作为编译对象,因为编译发生在方法执行过程中,因此成为栈上替换(OSR编译)

热点探测判定方式有两种:
1.基于采样的热点探测:虚拟机周期性的检查各个线程的栈顶,如果某个方法经常出现在栈顶,则判定为“热点方法”。(简单高效,可以获取方法的调用关系,但容易受线程阻塞或别的外界因素影响扰乱热点探测)
2.基于计数的热点探测:虚拟机为每个方法建立一个计数器,统计方法的执行次数,超过一定阈值就是“热点方法”。(需要为每个方法维护计数器,不能直接获取方法的调用关系,但是统计结果精确严谨)  

HotSpot virtual machine using a second, it prepares two types of counters for each method: method call counter and back counter side, the following figure represents a method call trigger counter-time compilation:

如果不做任何设置,执行引擎会继续进入解释器按照解释方式执行字节码,直到提交的请求被编译器编译完成,下次调用才会使用已编译的版本。另外,方法调用计数器的值也不是一个绝对次数,而是一段时间之内被调用的次数,超过这个时间,次数就减半,这称为计数器热度的衰减。

下图表示回边计数器触发即时编译:

回边计数器没有计数器热度衰减的过程,因此统计的就是绝对次数,并且当计数器溢出时,它还会把方法计数器的值也调整到溢出状态,这样下次进入该方法的时候就会执行标准编译过程。

编译优化技术

虚拟机设计团队几乎把对代码的所有优化措施都集中在了即时编译器之中,那么在编译器编译的过程中,到底做了些什么事情呢?下面将介绍几种最有代表性的优化技术:
公共子表达式消除
如果一个表达式E已经计算过了,并且先前的计算到现在E中所有变量的值都没有发生变化,那么E的这次出现就成为了公共表达式,可以直接用之前的结果替换。
例:int d = (c * b) * 12 + a + (a + b * c) => int d = E * 12 + a + (a + E)

数组边界检查消除
Java语言中访问数组元素都要进行上下界的范围检查,每次读写都有一次条件判定操作,这无疑是一种负担。编译器只要通过数据流分析就可以判定循环变量的取值范围永远在数组长度以内,那么整个循环中就可以把上下界检查消除,这样可以省很多次的条件判断操作。

另一种方法叫做隐式异常处理,Java中空指针的判断和算术运算中除数为0的检查都采用了这个思路:

if(foo != null){
    return foo.value;
}else{ throw new NullPointException(); } 使用隐式异常优化以后: try{ return foo.value; }catch(segment_fault){ uncommon_trap(); } 当foo极少为空时,隐式异常优化是值得的,但是foo经常为空,这样的优化反而会让程序变慢,而HotSpot虚拟机会根据运行期收集到的Profile信息自动选择最优方案。

Methods within the Union
in the method can remove costs associated method calls, but also established a good foundation for other optimizations, thus within the various compilers will generally associated optimization on optimizing the most forward position of the sequence, but because Java objects the default method is a virtual method, so the method calls need to be selected at run-time polymorphism, in order to solve the problem inline virtual methods, first introduced the technology "type inheritance relationship analysis (CHA)" is.

1.在内联时,若是非虚方法,则可以直接内联  
2.遇到虚方法,首先根据CHA判断此方法是否有多个目标版本,若只有一个,可以直接内联,但是需要预留一个“逃生门”,称为守护内联,若在程序的后续执行过程中,加载了导致继承关系发生变化的新类,就需要抛弃已经编译的代码,退回到解释状态执行,或者重新编译。
3.若CHA判断此方法有多个目标版本,则编译器会使用“内联缓存”,第一次调用缓存记录下方法接收者的版本信息,并且每次调用都比较版本,若一致则可以一直使用,若不一致则取消内联,查找虚方法表进行方法分派。

Escape analysis
basic behavior analysis target escape analysis dynamic scope is, when an object is referenced outside the method, a method called escape; when accessed by an external thread, the thread is called escape. If we can prove that an object can not be referenced outside the method or process may be thought that some optimization variables:

1.栈上分配:如果确定一个对象不会逃逸,则可以让它分配在栈上,对象所占用的内存空间就可以随栈帧出栈而销毁。这样可以减小垃圾收集系统的压力。  
2.同步消除:线程同步相对耗时,如果确定一个变量不会逃逸出线程,那这个变量的读写不会有竞争,则对这个变量实施的同步措施也就可以消除掉。  
3.标量替换:如果逃逸分析证明一个对象不会被外部访问,并且这个对象可以被拆散的话,那么程序真正执行的时候可以不创建这个对象,改为直接创建它的成员变量,这样就可以在栈上分配。

But there is no guarantee that escape analysis of the performance gain must be higher than it consumes, so the technology is not very mature.

java with C / C ++ compiler Comparative

Java虚拟机的即时编译器与C/C++的静态编译器相比,可能会由于下面的原因导致输出的本地代码有一些劣势:
1.即时编译器运行占用的是用户程序的运行时间,具有很大的时间压力,因此不敢随便引入大规模的优化技术;
2.Java语言是动态的类型安全语言,虚拟器需要频繁的进行动态检查,如空指针,上下界范围,继承关系等;
3.Java中使用虚方法频率远高于C++,则需要进行多态选择的频率远高于C++;
4.Java是可以动态扩展的语言,运行时加载新的类可能改变原有的继承关系,许多全局的优化措施只能以激进优化的方式来完成;
5.Java语言的对象内存都在堆上分配,垃圾回收的压力比C++大

然而,Java语言这些性能上的劣势换取了开发效率上的优势,并且由于C++编译器所有优化都是在编译期完成的,以运行期性能监控为基础的优化措施都无法进行,这也是Java编译器独有的优势。

Micro-channel public number of rivers and lakes] [Java technology Java, a technical engineer Ali station. (No reply after public concern "Java" Java can receive basic, advanced, and the project architect and other free learning materials, more databases, distributed, service and other popular micro learning video technology, rich content, both theory and practice, also presented will be the original author of the study guide Java, Java programmer interview guide and other dry goods resources)

Guess you like

Origin www.cnblogs.com/xll1025/p/11369843.html