jvm|JVM底层原理之JIT编译器如何通过方法内联优化代码

jvm|JVM底层原理之JIT编译器如何通过方法内联优化代码

JVM底层原理之JIT编译器如何通过方法内联优化代码
可能我们对JIT是如何将字节码编译成机器码的过程没多少兴趣 , 但是我们可以学习一下它采用了哪些优化技术和手段 , 毕竟它不仅是简单的进行编译 , 还进行了很多优化的操作 。
①方法内联方法内联介绍:
调用一个方法通常要经历压栈和出栈 , 如果当前执行的方法又调用了其他方法 , 就会加大时间和空间的开销 。 因为如果我们是在方法1的执行途中调用方法2 , 就需要将程序执行顺序转移到方法2的内存地址 , 将方法2的内容执行完后 , 再返回到方法1的位置继续执行 。 而这需要在执行方法2前 , 保存好执行到一半的方法1地址和环境 , 以便执行完方法2后进行恢复现场的工作(可以理解为一种上下文切换的精简版) 。
如果一层一层的下去 , 每层都是一笔开销 , 而如果我们将方法2的全部代码复制到方法1进行调用的地方 , 这样在调用方法1时 , 代码的逻辑没有任何改变 , 但是却不需要花费嵌套调用的开销了 , 这就是方法内联 。
代码举例:
首先 , 编译器读取的是字节码.class文件 , 当然是不可能读取java文件的 , 但是这里我还是用java代码举了个例子 , 主要是方便大家理解的是这么个意思的 。
进行方法内联前:
//方法1private int test(int x int y) {        int result=add(xy);\t\treturn result;
//方法2private int add(int s1 int s2) {\t\treturn s1+s2;
\t


方法内联后:
private int test(int x int y) {        int result=x+y;\t\treturn result;


参数调整:
方法内联不是百分百会被执行的 , 它会参考方法调用层数 , 目标方法的调用次数及字节码大小进行判断 , 我们也可以通过一些参数调整这个优化技术 。


说实话我不怎么喜欢贴参数配置 , 因为80%的人是不需要修改这些配置的 , 剩下20%在需要修改时会自己去百度 。。。 而且还要付出自己瞎JB改虚拟机参数的代价(大佬除外) 。 所以这里主要看看我们可以定制哪些参数就行了 , 不用记参数指令 。
  • 如果方法是经常执行的 , 方法小于325字节的会进行内联优化 , 可以用参数-XX:MaxFreqInlineSize=N调整这个字节大小 。
  • 如果方法不经常执行 , 方法小于35字节才会进行内联优化 。 可以用参数-XX:MaxInlineSize=N调整这个字节大小 。
  • -XX:CompileCommand配置中的inline指令指定的方法会被强制内联 , dontinline和exclude指定的方法始终不会被内联
  • @ForceInline注解的jdk内部方法会被强制内联 , @DontInline注解jdk内部方法始终不会被内联
  • 方法的符号引用未被解析、目标方法所在类未被初始化、或目标方法是native方法 , 都会导致方法无法内联
  • C2默认不支持9层以上的方法调用(可通过-XX:MaxInlineLevel调整) , 以及1层的直接递归调用(可通过-XX:MaxRecursiveInlineLevel调整)
【jvm|JVM底层原理之JIT编译器如何通过方法内联优化代码】另外还有不少其他的jvm参数 , 就不全贴了 , 可以自己去查一下 , 基本上参数名里带inline的都是关于方法内联的参数 。