【问题标题】:Are there inline functions in java?java中有内联函数吗?
【发布时间】:2010-01-19 19:23:00
【问题描述】:

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

【问题讨论】:

标签: java inline-code


【解决方案1】:

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

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

更多资源:

  1. Article: The Java HotSpot Performance Engine: Method Inlining Example

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

【讨论】:

    【解决方案2】:

    不,java 中没有inline function。是的,当放置在公共类中时,您可以在代码中的任何地方使用公共静态方法。 java 编译器可能会在静态或最终方法上执行inline expansion,但这不能保证。

    通常,此类代码优化是由编译器结合 JVM/JIT/HotSpot 对经常使用的代码段进行的。此外,其他优化概念,如参数的寄存器声明,在 java 中是未知的。

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

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

    【讨论】:

    • final 对 JIT 内联没有影响
    • +1,但是我们如何测试方法的编译版本是否被内联?
    • @Pacerier 但是我们为什么要测试是否内联?
    【解决方案3】:

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

    【讨论】:

    • 大多数 java 编译器从不内联方法调用。大多数情况下,JVM 都会这样做。
    • 感谢您澄清这一点。我不确定具体发生在哪个阶段。我将编辑我的帖子以反映这一点。
    • @ThomasOwens 确实如此,但它不公开jdk.internal.vm.annotation.ForceInline
    【解决方案4】:

    你上面说的是对的。有时 final 方法被创建为内联,但没有其他方法可以在 java 中显式创建内联函数。

    【讨论】:

    • 最终方法不保证是内联的。
    • 在 HotSpot 上,添加 final 甚至不会影响方法是否内联。
    • @Thomas - 这就是为什么我说“有时是最终方法......”
    • @TomHawtin-tackline 你有这方面的权威来源吗?据我所知,final 方法可以在不使用类型保护的情况下内联,这意味着修饰符使内联方法比没有修饰符更有效。我知道 Jikes RVM 在决定是否内联时会考虑到这一点。你确定 HotSpot 没有做类似的事情吗?
    【解决方案5】:

    嗯,在 java 中有一些方法可以称为“内联”方法,但取决于 jvm。编译后,如果方法的机器码小于35字节,则立即转入内联方法,如果方法的机器码小于325字节,则可以转入内联方法,具体取决于jvm。

    【讨论】:

    【解决方案6】:

    现实生活中的例子:

    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 类,因为在运行时不需要它。

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

    至于证明在编译过程中控制类的方法是否内联到另一个类,尝试在类路径中不包含控制类的情况下运行另一个类。

    【讨论】:

      【解决方案7】:

      所以,似乎没有,但是您可以使用 guava 或等效的 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);
      

      是的,这是死代码,只是为了举例说明如何创建一个复杂的代码块(在 {} 内)来做一些如此具体的事情,不应该打扰我们为它创建任何方法,AKA 内联!

      【讨论】:

      • 似乎是一个合理的想法。你有一个不使用谷歌公共库的版本吗?
      【解决方案8】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-23
        • 2012-06-22
        • 2016-03-30
        • 2017-03-09
        • 2016-07-18
        • 2022-12-07
        • 2012-09-13
        • 2010-09-16
        相关资源
        最近更新 更多