龙空技术网

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

白夜java 61

前言:

当前朋友们对“内联java”大约比较讲究,小伙伴们都需要了解一些“内联java”的相关知识。那么小编同时在网络上搜集了一些对于“内联java””的相关文章,希望小伙伴们能喜欢,咱们一起来了解一下吧!

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(x,y);		return result;}//方法2private int add(int s1, int s2) {		return s1+s2;}	

方法内联后:

private int test(int x, int y) {        int result=x+y;		return 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参数,就不全贴了,可以自己去查一下,基本上参数名里带inline的都是关于方法内联的参数。

标签: #内联java