Java中有内联函数吗?


112

在Java中是否有内联函数的概念,或其替代了其他概念?如果有,如何使用?我听说publicstaticfinal方法是内联函数。我们可以创建自己的内联函数吗?


4
只是为了澄清,您的意思是en.wikipedia.org/wiki/Inline_function,而不是en.wikipedia.org/wiki/Anonymous_function,对吗?
JW。

3
作为次要评论,过早的优化是万恶之源。如果没有完全了解public,static和final的性质,您将无法真正理解内联的影响-这取决于您使用的JVM。确保首先回答为什么需要内联某些东西:几乎可以肯定,您可以在其他地方进行更高的ROI优化。
纳撒尼尔·福特

Answers:


123

在Java中,优化通常在JVM级别完成。在运行时,JVM执行一些“复杂”分析以确定要内联的方法。内联可能非常激进,而Hotspot JVM实际上可以内联非最终方法。

Java编译器几乎从不内联任何方法调用(JVM在运行时完成所有这些操作)。它们确实内联编译时间常数(例如,最终的静态原始值)。但不是方法。

有关更多资源:

  1. 文章:Java HotSpot性能引擎:方法内联示例

  2. Wiki:OpenJDK中的内联,未完全填充,但包含指向有用讨论的链接。


15

不,Java中没有内联函数。是的,当放置在公共类中时,可以在代码中的任何位置使用公共静态方法。Java编译器可以在静态或最终方法上进行内联扩展,但是不能保证。

通常,此类代码优化是由编译器与JVM / JIT / HotSpot结合使用的,用于经常使用的代码段。同样,其他优化概念(如参数的寄存器声明)在Java中也不为人所知。

优化不能通过Java中的声明来强制执行,而是通过编译器和JIT完成。在许多其他语言中,这些声明通常只是编译器提示(您可以声明比处理器更多的寄存器参数,其余的将被忽略)。

将Java方法声明为static,final或private也是对编译器的提示。您应该使用它,但不能保证。Java性能是动态的,而不是静态的。由于类加载,对系统的第一次调用总是很慢。下次调用会更快,但是根据内存和运行时,最常见的调用会在正在运行的系统中进行优化,因此服务器可能会在运行时变得更快!


3
final对JIT内联没有影响
Steve Kuo

1
+1,但是如何测试方法的编译版本是否内联?
Pacerier 2014年

@Pacerier但是为什么要测试是否有内联?
Arne Burmeister

14

Java没有提供手动建议应该内联方法的方法。正如@notnoop在评论中所说,内联通常由JVM在执行时完成。


3
大多数Java编译器从不内联方法调用。通常,JVM会这样做。
notnoop 2010年

感谢您澄清这一点。我不确定到底发生了什么阶段。我将编辑我的帖子以反映这一点。
Thomas Owens 2010年

@ThomasOwens可以,但是不是公开的jdk.internal.vm.annotation.ForceInline
尤金(Eugene)

4

你上面说的是正确的。有时最终方法会以内联方式创建,但是没有其他方法可以在Java中显式创建内联函数。


5
最终方法不能保证是内联的。
Thomas Owens 2010年

4
在HotSpot上,添加final方法对该方法是否内联甚至没有任何区别。
Tom Hawtin-大头钉

4
@Thomas-这就是为什么我说“有时是最后的方法……”
GreenieMeanie 2010年

@ TomHawtin-tackline您是否对此有权威来源?据我所知,可以在不使用类型保护的情况下内联最终方法,这意味着修饰符使内联方法比不使用修饰符更有效。我知道Jikes RVM在决定是否内联时会考虑到这一点。您确定HotSpot不会做类似的事情吗?
Jannik Jochem 2015年

2

现实生活中的例子:

public class Control {
    public static final long EXPIRED_ON = 1386082988202l;
    public static final boolean isExpired() {
        return (System.currentTimeMillis() > EXPIRED_ON);
    }
}

然后在其他课程中,如果代码已过期,我可以退出。如果我从另一个类中引用EXPIRED_ON变量,则该常数将内联到字节码中,这使得很难在代码中查找检查到期日期的所有位置。但是,如果其他类调用isExpired()方法,则会调用实际方法,这意味着黑客可以将isExpired方法替换为始终返回false的另一个方法。

我同意强制编译器将静态final方法内联到所有引用该方法的类中会很好。在这种情况下,您甚至不需要包含Control类,因为在运行时不需要。

根据我的研究,这是无法完成的。也许某些混淆器工具可以做到这一点,或者您可以修改构建过程以在编译之前编辑源代码。

至于证明在编译过程中控件类中的方法是否内联到另一个类,请尝试在类路径中运行没有Control类的其他类。


2

好吧,在Java中有一些方法可以称为“内联”方法,但取决于jvm。编译后,如果方法的机器代码小于35字节,则将立即传输到内联方法;如果方法的机器代码小于325字节,则可以将其转换为内联方法,具体取决于jvm。


1
这些是Oracle VM的默认值,请参阅docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
rmuller

0

因此,似乎没有什么用,但是您可以使用番石榴或等效的Function类实现来使用此解决方法,因为该类非常简单,例如:

    assert false : new com.google.common.base.Function<Void,String>(){
        @Override public String apply(Void input) {
            //your complex code go here
            return "weird message";
        }}.apply(null);

是的,这是死代码,只是为了举例说明如何创建复杂的代码块(在{}内)以完成如此​​具体的操作,因此不应该困扰我们为它创建任何方法,即内联!


似乎是一个合理的想法。您是否有不使用Google公共库的版本?
ragerdl

0

Java9有一个“提前”编译器,该编译器在编译时而不是运行时进行了一些优化,这可以看作是内联的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.