【问题标题】:What is method inlining? [duplicate]什么是方法内联? [复制]
【发布时间】:2011-04-24 21:51:22
【问题描述】:

我一直在努力理解这到底意味着什么:

内联函数

在 C++ 中,定义在 类声明。 (2) 一个函数 调用编译器替换为 函数的实际代码。这 关键字 inline 可用于提示 执行内联的编译器 成员主体的扩展或 非成员函数。

内联

用副本替换函数调用 函数的代码在 编译。

例如它是这样写的:

当一个方法是final时,它可能是 内联。

这里:http://www.roseindia.net/javatutorials/final_methods.shtml

你能给我一个例子或什么,或者基本上帮助我理解“它可能是内联的”是什么意思。

谢谢。

【问题讨论】:

标签: java function methods


【解决方案1】:

内联是由 Java Just-In-Time 编译器执行的优化。

如果你有方法:

public int addPlusOne(int a, int b) {
  return a + b + 1;
}

你这样称呼:

public void testAddPlusOne() {
  int v1 = addPlusOne(2, 5);
  int v2 = addPlusOne(7, 13);

  // do something with v1, v2
}

编译器可能决定用函数体替换你的函数调用,所以结果实际上看起来像这样:

public void testAddPlusOne() {
  int v1 = 2 + 5 + 1;
  int v2 = 7 + 13 + 1

  // do something with v1, v2
}

编译器这样做是为了节省实际进行函数调用的开销,这将涉及将每个参数推入堆栈。

这显然只能用于非虚拟功能。考虑如果方法在子类中被覆盖并且包含该方法的对象的类型直到运行时才知道会发生什么......编译器如何知道要复制哪些代码:基类的方法体或子类的方法体?由于在 Java 中默认所有方法都是虚拟的,因此您可以将那些不能被覆盖的方法显式标记为 final(或将它们放入 final 类中)。这将帮助编译器确定该方法永远不会被覆盖,并且内联是安全的。 (请注意,编译器有时也可以对非最终方法做出此决定。)

另外,请注意引文中的可能一词。最终方法不能保证是可内联的。有多种方法可以保证方法不能被内联,但无法强制编译器内联。无论如何,它几乎总是比你更清楚内联会帮助还是损害结果代码的速度。

请参阅wikipedia,以全面了解好处和问题。

【讨论】:

  • 很好的答案,但请注意:如果您有一个 覆盖的非最终方法,那么一个好的 JIT 可以解决这个问题并将其内联。如果您随后加载了一个覆盖它的类,它可以撤消内联。
  • 好点,我已将其添加到答案正文中。
  • 解释性很强,感谢您的出色回答。
【解决方案2】:

假设您有一个如下所示的类:

public class Demo {
    public void method() {
        // call printMessage
        printMessage();
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}

printMessage 的调用可以通过以下方式“内联”:

public class Demo {
    public void method() {
        // call printMessage
        System.out.println("Hello World"); // <-- inlined
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}

(这实际上不是在 Java 级别(甚至不是字节码级别)而是在 JIT 编译期间完成的,但上面的示例说明了内联的概念。)

现在考虑如果printMessage 方法被另一个类重载会发生什么,如下所示:

class SubDemo extends Demo {
    public void printMessage() {
        System.out.println("Something else");
    }
}

现在如果编译器内联对Demo.printMessage 的调用,它将被System.out.println("Hello World"); 卡住,如果对象实际上是SubDemo 的实例,这将是错误

但是,如果方法被声明为final,在任何情况下都不会出现这种情况。如果方法是“final”,则意味着它永远不会被新定义覆盖,因此,内联它是安全的!

【讨论】:

  • 也是不错的答案,但作为从另一个答案复制的注释:如果您有一个不覆盖的非最终方法,那么一个好的 JIT 可以解决这个问题并将其内联。如果您随后加载了一个覆盖它的类,它可以撤消内联。
  • 解释性很强,感谢您的出色回答。
【解决方案3】:

调用函数不是免费的。机器必须维护一个堆栈帧,以便在被调用函数完成时可以返回到调用代码段。维护堆栈(包括在此堆栈上传递函数参数)需要时间。

当一个函数被内联时,编译器用函数的代码替换对该函数的调用,这样就可以避免函数调用在运行时的性能损失。这是编程中的经典权衡之一:运行时代码变得更大(占用更多内存),但运行速度更快。

【讨论】:

  • 谢谢。在第一段,你真的是对的。
猜你喜欢
  • 2021-12-13
  • 2014-12-27
  • 2013-05-16
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多