JAVA即时编译--深入理解JAVA虚拟机读书笔记

解释器: 每次读取一代码,将代码转换成对应JVM执行的指令,然后调用JVM指令执行。
即时编译:将源代码直接生成符合本地物理机可识别的机器语言。
解释器对同样的代码每次都要重新翻译成JVM指令,效率低下。即时编译器的好处在于可以对代码进行深度优化,同时提高效率。

即时编译(JIT)

JIT是just in time的缩写,也就是即时编译编译器。
通常通过javac将程序源代码编译成class文件,JVM通过解释class文件内部的字节码,将其翻译成对应的机器指令,逐条读入,逐条解释翻译。显然,经过解释执行,其执行速度肯定比可执行的二进制字节码慢。为了提高JVM的执行速度,引入了JIT技术。

1. 即时编译过程图

2. 客户的模式或服务器模式

JIT编译器在运行程序时有两种编译模式可以选择,并且其会在运行时决定使用哪一种以达到最优性能。当虚拟机运行在-client 模式的时候,使用的是一个代号为 C1 的轻量级编译器,而-server 模式启动的虚拟机采用相对重量级代号为 C2 的编译器。C2 比 C1 编译器编译的相对彻底,服务起来之后,性能更高。
可以通过java -version查询当前系统使用的模式:
java信息

  1. Server VM说明当前系统模式的是server模式(也可通过-client或者-server指定)
  2. mixed mode说明当前JVM使用解释器与即时编译混合搭配使用。参数-Xint强制虚拟机运行解释模式,-Xcomp强制虚拟机运行编译模式,只是在无法编译的情况下使用解释器运行。【mixed mode | compiled mode | interpreted mode】

即时编译本地代码需要占用程序运行时间,解释器还需要收集性能监控信息,对解释器的执行速度有影响。

HotSpot虚拟机内置两个即时编译器:Client Compiler和Server Compiler,称为C1和C2,分别用在客户端和服务端。C1能够获取更高的编译速度,而C2获取更好的编译质量。

3. 编译对象与触发条件

在运行期会被JVM编译即时编译器编译的对象包括【热点代码】:

  • 被多次调用的方法
    这情况,是由方法调用触发的编译,编译器会将整个方法作为编译对象;
  • 被多次执行的循环体
    这中情况解决一个方法调用少次,但方法体内存在循环次数较多循环体问题,这样循环体代码也被重复执行多次,也认为是热点代码。编译器依然会将整个方法作为编译对象。

编译热点代码触发的阈值在client下默认1500次,server模式下默认10000次,可以通过-XX:compileThreshold设定。如果不做设置方法统计执行次数是在一定时间内被调用的次数,如果超过一定是不被调用,则计数器将会减半,这个过程称为“计数器热度衰退”,可以通过 -XX:UseCounterDecay来关闭热度衰退,还可以通过 -XX:CounterHalfLifeTime设置半衰退时间周期(单位秒)。

4. 编译器优化

当JVM编译代码时,它将汇编指令保存在代码缓存,代码缓存具有固定大小,一旦它被填满,JVM将不能编译更多的代码。 -XX:ReservedCodeCacheSize 增加代码缓存的大小(默认32m)。编译器线程的数量可以通过 -XX:CICompilerCount=N flag 进行调节设置。

即时编译在编译期的优化策略:

  1. 方法内联
  2. 冗余访问消除
  3. 无用代码消除
  4. 公共子表达式消除
  5. 数组范围检查消除
  6. 逃逸分析
  7. 其他N多策略

5. 即时编译器日志

public class TrueFalseVO {
	private static final  int NUM=15000;
	
	private static int doubleValue(int i) {
	    for (int j = 0; j < NUM; j++) {
	
	    }
	    return i*2;
	}
	
	private static long caclSum(){
	    long  sum = 0;
	    for (int i = 0; i < 100; i++) {
	        sum = doubleValue(i) + sum;
	    }
	    return sum;
	}
	
	/**
	 * -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
	 * PrintCompilation打印及时编译信息
	 * PrintInlining打印方法内联信息
	 */
	public static void main(String[] args){
	    for (int i = 0; i < NUM; i++) {
	        caclSum();
	    }
	}
}
   // 即时编译日志
    189    1     n 0       java.lang.System::arraycopy (native)   (static)
    189    2     n 0       java.lang.Thread::currentThread (native)   (static)
    195    3       3       java.lang.AbstractStringBuilder::<init> (12 bytes)
    195    4       4       java.lang.String::hashCode (55 bytes)
    196    5       4       java.lang.String::charAt (29 bytes)
    197    6       1       sun.instrument.TransformerManager::getSnapshotTransformerList (5 bytes)
    199    7       3       java.lang.Character::toLowerCase (6 bytes)
    199    8       3       sun.nio.cs.UTF_8$Encoder::encode (359 bytes)
    200    9       3       java.lang.String::length (6 bytes)
    201   12       3       java.lang.Object::<init> (1 bytes)
    201   10       3       java.lang.Math::min (11 bytes)
    201   13       3       java.lang.String::indexOf (7 bytes)
    201   14       4       java.lang.String::indexOf (70 bytes)
    201   11       3       java.lang.ref.SoftReference::get (29 bytes)
    204   15       3       java.lang.ThreadLocal::getMap (5 bytes)
    204   16       3       java.lang.String::startsWith (72 bytes)
    204   17       3       java.lang.String::startsWith (7 bytes)
    204   18       3       java.util.zip.ZipFile::ensureOpen (37 bytes)
    204   19       3       java.util.zip.ZipCoder::getBytes (192 bytes)
    207   25       3       java.lang.AbstractStringBuilder::ensureCapacityInternal (16 bytes)
    207   24       3       java.lang.String::<init> (82 bytes)
    207   23       3       java.lang.StringBuilder::append (8 bytes)
    207   20       3       java.util.zip.ZipCoder::encoder (35 bytes)
    208   21       3       java.nio.charset.CharsetEncoder::reset (11 bytes)
    208   22       1       java.lang.ThreadLocal::access$400 (5 bytes)
    208   26  s    1       java.util.Vector::size (5 bytes)
    210   27 %     3       com.netease.ecnrypt.Main::doubleValue @ 2 (19 bytes)
    210   28       3       com.netease.ecnrypt.Main::doubleValue (19 bytes)
    211   29 %     4       com.netease.ecnrypt.Main::doubleValue @ 2 (19 bytes)
    211   27 %     3       com.netease.ecnrypt.Main::doubleValue @ -2 (19 bytes)   made not entrant
    212   30       4       com.netease.ecnrypt.Main::doubleValue (19 bytes)
    212   28       3       com.netease.ecnrypt.Main::doubleValue (19 bytes)   made not entrant
    214   31       3       com.netease.ecnrypt.Main::caclSum (26 bytes)
    215   32 %     4       com.netease.ecnrypt.Main::caclSum @ 4 (26 bytes)
    217   33       4       com.netease.ecnrypt.Main::caclSum (26 bytes)
    218   31       3       com.netease.ecnrypt.Main::caclSum (26 bytes)   made not entrant

JIT即时编译: https://www.ibm.com/developerworks/cn/java/j-lo-just-in-time/index.html
《Java虚拟机第二版》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深入理解Java虚拟机(第四版)》是一本非常重要的Java虚拟机相关的权威书籍,对于深入理解Java虚拟机的原理和机制具有很大的帮助。 这本书的第四版相比之前的版本,在内容上进行了全面的更新和拓展。首先,这本书详细介绍了Java虚拟机的整体架构和工作原理,包括Java虚拟机的类加载、运行时数据区、垃圾回收、即时编译等方面的知识。同时,也对Java内存模型进行了详细的讲解,让读者能够更好地理解Java多线程编程的内存可见性、原子性等问题。 其次,在第四版中,作者还新增了对Java虚拟机动态编译技术的讲解。这是一项非常重要的技术,能够在运行时动态地将Java字节码编译成本地代码,并进行优化。通过深入了解动态编译技术,读者可以更好地利用Java虚拟机的性能,提高程序的运行效率。 最后,这本书还介绍了一些常见的Java虚拟机性能调优手段,包括如何通过调整Java虚拟机的参数和使用性能分析工具来提高程序性能。这对于开发人员解决实际的性能问题非常有帮助。 总之,《深入理解Java虚拟机(第四版)》是一本非常权威且全面的Java虚拟机相关书籍,通过学习这本书,读者可以深入了解Java虚拟机的工作原理和机制,并能够运用这些知识来解决实际的性能问题。无论是对于Java开发人员还是对于Java虚拟机感兴趣的人来说,这本书都是一本值得阅读的好书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值