点击上方蓝字,记得关注我们!
JVM之JIT优化技术(一)
引言
本文是JVM之JIT优化技术的开篇,这个在接下来的几章中将会详细讲解JIT优化技术。关于JVM优化和如何使用JIM编译和不同的优化技术让程序运行的更快有很多争论。其实,有很多优秀的文章是可以被找到的,但是对于我自己来说,我还想看看关于这方面的应用,因此我决定对此去深挖和进行一些简单的测量。
01 延迟编译
Java编译器读取Java源文件并且将它们编译称为class文件。不同于其他的编译器,例如gcc或者ghci ,Javac编译器不会对于特定的平台给予一个依赖于平台的代码,但是它会产生字节码。
字节码是由一些便携式的指令集组成,在这些指令集中,所有的操作码都是被表示为一个字节。指令在虚拟机上被执行。由于这一点,字节码是平台无关性的,但是这样会造成一些性能损失,由于这些字节码的性能比起优化后的本地代码差。
与上面提到的gcc等编译器不同的是,字节码存在很少的优化,例如类嵌常量等。
这就是说,产生的字节码与源代码的原始特性相似。正是由于这种特点,这是的反编译程序称为可能,并且简化了字节码操作,这是伟大的,例如如果你决定为失败的测试收集变量分配,这就变得有可能。
早期的JVM版本是没有任何的优化,JVM使用字节码工作主要通过直接翻译字节码。为了使程序更加快的执行,或者说优化程序,在JDK1.3时,HotSpot虚拟机提供了及时编译,即JIT技术,使运行时能够执行优化后的代码,而不是缓慢的解释字节码指令。
JVM需要花费一些时间去监视那些在虚拟机上运行的代码的情况。例如,它需要分析那部分代码经常被执行去决定这个部分代码哪些是值得优化的,并且分析代码如何执行去决定哪些优化可以被应用。
JIT编译器生成针对目标体系结构的优化代码,以动态替代解释版本。这些编译发生在后台线程中,因此它将不会中断程序执行。
一些优化需要更为详细的概要文件,一些并不需要,因此一些优化可以比另一些更早的应用,以及如果一个程序运行很长时间其中的一些优化方法才值得花时间去做。
在JVM中,存在两种编译器:客户端编译器和服务端编译器。
客户端编译器使用简单的优化,因此它需要较少的时间去分析运行的代码。这非常适用于运行时间较少的程序,提供更快地启动速度,但是只有少量优化。服务端编译器主要针对于运行时间长的应用,收集大量数据去分析。这点启动慢,但是提供了较多的优化技术。
使用Java6时,必须在客户端编译器和服务端编译器只能选择其一。在Java7中,有个选项时使用多层编译,从Java8开始在JVM中这是一个默认的行为。这个方法同时使用了客户端和服务端编译器。
在启动和配置它后,虚拟机使用解释其去执行那些没有优化的代码,并且决定使用什么优化。对于每一个方法记录调用的次数,如果他超过了客户端编译器的阈值,那么它使得该方法有资格由客户端编译器进行优化,因此客户端编译器将方法排队用于编译。与客户端编译器相似,调用次数达到一个确定的阈值,服务器编译器也会优化它。
优化可以应用于环回边缘。VM计算循环完成执行的次数,类似于方法调用的次,它会在执行多次后对循环体进行排队以进行编译。此技术称为堆栈互换(OSR),它允许VM在运行代码的不同实现(解释或优化)之间切换。
很多优化都是基于以前手机的运行时数据形成的有根据的猜测。以后,如果有新的信息到来证明这个假设是错误的,VM将会反优化相关代码去阻止不正确的行为。JVM验证使用不常见的陷阱进行优化的假设。如果没有正确假设,这将触发VM去回转到解释模式,并且重新编译受影响的代码。
哪些编译优化后的代码被存储在一个特殊的堆中,这堆被称为代码缓存,Code Cache。代码被存在在那里,直到相关的类被卸载或者代码没有被去优化。代码缓存有限定的大小,因此,如果他耗尽空间,以后的代码将不被优化,这将导致性能问题。在我的实验中,这极少的发生,即使在很大的应用程序,但是如果它的默认值太小在你的app中,或者你故意缩小Code Cache空间,那么JVM将会抱怨它:
Java HotSpot(TM) 64-Bit Server VM warning: CodeCache is full. Compiler has been disabled.
Java HotSpot(TM) 64-Bit Server VM warning: Try increasing the code cache size using -XX:ReservedCodeCacheSize=
CodeCache: size=3072Kb used=2528Kb max_used=2536Kb free=544Kb
bounds [0x00007f12efae5000, 0x00007f12efde5000, 0x00007f12efde5000]
total_blobs=989 nmethods=629 adapters=272
compilation: disabled (not enough contiguous free space left)
02总结
JVM推迟编译都可以获得更多关于目标体系结构和代码动态行为的信息的时候。与静态预编译相比,动态及时编译有如下特点:
1.将运行信息和数据考虑在内使最优化称为可能
2.使用开销哪些开销呢,就是程序启动慢,以后将达到性能巅峰。
3.你自己不必在不同的平台编译你的代码,JVM将会帮你完成这一点。
▼
往期精彩回顾
▼
数据结构之布隆过滤器
Java并发之Monitor实现
Java中Vector的操作一定是线程安全的嘛?