什么是方法内联?

发布于 2024-09-27 10:56:40 字数 567 浏览 1 评论 0原文

我一直试图理解这真正意味着什么:

内联函数

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

内联

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

例如,它是这样写的:

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

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

你可以吗给我一个例子或其他东西,或者基本上帮助我理解“它可能被内联”的含义。

谢谢。

I've been trying to understand what that really means :

inline function

In C++, a member function defined in
the class declaration. (2) A function
call that the compiler replaces with
the actual code for the function. The
keyword inline can be used to hint to
the compiler to perform inline
expansion of the body of a member or
nonmember function.

inline

To replace a function call with a copy
of the function's code during
compilation.

For example it is written something like :

When a method is final, it may be
inlined.

Here : http://www.roseindia.net/javatutorials/final_methods.shtml

Can you give me an example or something or basically help me to understand what "it may be inlined" means.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦里°也失望 2024-10-04 10:56:40

内联是 Java 即时编译器执行的优化。

如果你有一个方法:

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 以全面了解优点和问题。

Inlining is an optimization performed by the Java Just-In-Time compiler.

If you have a method:

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

which you call like this:

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

  // do something with v1, v2
}

the compiler may decide to replace your function call with the body of the function, so the result would effectively look like this:

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

  // do something with v1, v2
}

The compiler does this to save the overhead of actually making a function call, which would involve pushing each parameter on to the stack.

This can clearly only be done for non-virtual functions. Consider what would happen if the method was overriden in a sub class and the type of the object containing the method isn't known until runtime...how would the compiler know what code to copy: the base class's method body or the sub class's method body? Since all methods are virtual by default in Java, you can explicitly mark those which cannot be overriden as final (or put them into a final class). This will help the compiler figure out that method will never be overriden, and it is safe to inline. (Note that the compiler can sometimes make this determination for non-final methods as well.)

Also, note the word may in the quote. Final methods aren't guaranteed to be inlineable. There are various ways you can guarantee a method isn't capable of being inlined, but no way to force the compiler to inline. It will almost always know better than you anyway when inlining will help vs. hurt the speed of the resulting code.

See wikipedia for a good overview of benefits and problems.

梦中的蝴蝶 2024-10-04 10:56:40

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

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,则在任何情况下都不会出现这种情况。如果该方法是“最终”的,则意味着它永远不能被新定义覆盖,因此,内联它是安全的!

Let's say you have a class that looks like this:

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

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

The call to printMessage could be "inlined" in the following way:

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

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

(This is actually not done on the level of Java (not even on bytecode level) but during JIT-compilation, but the example above illustrates the concept of inlining.)

Now consider what would happen if the printMessage method was overloaded by another class, like this:

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

Now if the compiler inlined the call to Demo.printMessage it would be stuck with System.out.println("Hello World"); which would be wrong in case the object was actually an instance of SubDemo.

However, if the method was declared final this would not under any circumstances be the case. If the method is "final" it means that it can never be overridden with a new definition, thus, it is safe to inline it!

三人与歌 2024-10-04 10:56:40

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

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

Calling a function is not free. The machine must maintain a stack frame so that it can return to the calling section of code when the called function is complete. Maintaining the stack (including passing function parameters on this stack) takes time.

When a function is in-lined, the compiler replaces the call to the function with the function's code so that one can avoid the performance penalty of a function call at run-time. This is one of the classic trade-offs in programming: the run-time code gets a little bigger (takes up more memory), but it runs a little faster.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文