Java 最终的方法是内联的吗?
Java final方法是否自动内联 很多书都说是,很多书都说不是 如果您的意思是“它们在编译期间内联了吗”,那么不,它们不会Java 最终的方法是内联的吗?,java,methods,inline,final,Java,Methods,Inline,Final,Java final方法是否自动内联 很多书都说是,很多书都说不是 如果您的意思是“它们在编译期间内联了吗”,那么不,它们不会 但是,静态final字段有时可以由编译器内联,例如原语和字符串。我认为这取决于您运行的JVM的哪个实现。当然,使方法成为final允许编译器选择进行这样的实现调整。但是,是否这样做也可能取决于其他因素,例如,如果它是一个巨大的方法,等等……方法的内联是由JIT编译器执行的,而不是javac 现代JIT编译器(包括Hotspot)通常可以内联甚至非最终方法,必要时适当地“
但是,静态final字段有时可以由编译器内联,例如原语和字符串。我认为这取决于您运行的JVM的哪个实现。当然,使方法成为final允许编译器选择进行这样的实现调整。但是,是否这样做也可能取决于其他因素,例如,如果它是一个巨大的方法,等等……方法的内联是由JIT编译器执行的,而不是javac 现代JIT编译器(包括Hotspot)通常可以内联甚至非最终方法,必要时适当地“撤销”优化。他们基本上非常聪明
简而言之:这完全取决于虚拟机。在我看来,你应该让你的方法成为最终的,而不是基于产生最干净代码的东西,而不是性能。我个人是“为继承而设计或禁止它”的粉丝,但这是一个不同的讨论:)
final
更多的是为设计添加语义,而不是告诉编译器或VM内联一些东西。现代虚拟机内联的不仅仅是final方法,所以这不是使用final
或试图预测太多运行时优化的好理由。有趣的问题促使我进一步研究它。我发现了两条有趣的评论-
- 那是自动的吗 内联是一个bug:
这里有一个更详细的机制。Hotspot决定是否内联是非常复杂的,取决于太多的考虑因素,但我不认为该方法是否标记为“final”是其中之一。原因是它已经知道该方法的多个实现是否已加载到VM中,因此也不必知道是否允许这样的实现
在任何情况下,只有非常小和简单的方法可以内联,甚至不是所有的方法。正如Jon所说,内联是由JIT编译器(在需要时)完成的,而不是在字节码生成级别。还要注意,有时内联可能会导致性能下降,因为它可能会造成相同代码在cpu一级缓存中多次出现的情况,从而删除其他代码的空间。一级缓存未命中比跳转到缓存函数对性能的影响更大 常量(也称为最终静态变量)是内联的 看看这个来检查一下
public class InlineTest {
final static int add(int x, int y) {
return x + y;
}
}
public class Main {
static final int DIVISOR = 7;
static void main(String[] args){
final int a = new Integer(args[0]);
final int b = new Integer(args[1]);
if (InlineTest.add(a, b) % DIVISOR == 0)
System.exit(InlineTest.add(a, b));
System.out.print("The sum is " + InlineTest.add(a, b));
}
}
这被翻译成:
0 new #2 <java/lang/Integer>
3 dup
4 aload_0
5 iconst_0
6 aaload
7 invokespecial #3 <java/lang/Integer/<init>(Ljava/lang/String;)V>
10 invokevirtual #4 <java/lang/Integer/intValue()I>
13 istore_1
14 new #2 <java/lang/Integer>
17 dup
18 aload_0
19 iconst_1
20 aaload
21 invokespecial #3 <java/lang/Integer/<init>(Ljava/lang/String;)V>
24 invokevirtual #4 <java/lang/Integer/intValue()I>
27 istore_2
28 iload_1
29 iload_2
30 invokestatic #5 <com/gamasoft/InlineTest/add(II)I>
33 bipush 7
35 irem
36 ifne 47 (+11)
39 iload_1
40 iload_2
41 invokestatic #5 <com/gamasoft/InlineTest/add(II)I>
44 invokestatic #7 <java/lang/System/exit(I)V>
47 getstatic #8 <java/lang/System/out Ljava/io/PrintStream;>
50 new #9 <java/lang/StringBuilder>
53 dup
54 invokespecial #10 <java/lang/StringBuilder/<init>()V>
57 ldc #11 <The sum is >
59 invokevirtual #12 <java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;>
62 iload_1
63 iload_2
64 invokestatic #5 <com/gamasoft/InlineTest/add(II)I>
67 invokevirtual #13 <java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;>
70 invokevirtual #14 <java/lang/StringBuilder/toString()Ljava/lang/String;>
73 invokevirtual #15 <java/io/PrintStream/print(Ljava/lang/String;)V>
76 return
0新#2
3次重复
4阿洛德0
5 iconst_0
6安培负载
7特别是#3
10调用虚拟设备#4
13史前1
14新#2
17次重复
18 aload_0
19 iconst_1
20安培负载
21特别是#3
24调用虚拟设备4
27史努比2
28 iload_1
29 iload_2
30房地产#5
33双推7
35伊雷姆
36 ifne 47(+11)
39 iload_1
40 iload_2
41房地产#5
44房地产#7
47 getstatic#8
50新#9
53次重复
54特别是#10
57最不发达国家11
59虚拟的#12
62 iload_1
63 iload_2
64房地产#5
67虚拟的#13
70虚拟的#14
73虚拟的#15
76返回
您可以看到,InlineTest.add静态函数已通过调用invokestatic被多次调用为什么要在意?(为什么这样至少有15个字符?@erikkallen-这就是“”的含义。:-)如果热点发现发生了这种情况,则内联将撤消。我相信它只是在所有受影响的类上重新启动整个JIT过程。OpenJDK做的和HotSpot做的一样吗?这不是以前“javac-O”做的吗?@Thorbjørn:不确定。。。我不这么认为,但我可能大错特错了。我想你的意思是说“javac编译”,因为另一个问题也是编译。