内联是什么?

时间:2009-10-10 00:39:19

标签: java c++ inlining

我指的是this discussion。我从未在C或C ++中编写任何代码。我没有任何CS背景。但是我已经作为Java开发人员工作了5年,现在我已经决定了解更多有关CS的知识并做一些追赶。

10 个答案:

答案 0 :(得分:35)

执行给定的代码时,无论何时调用标准函数,执行时间都略高于转储包含在该函数中的代码。每次函数中包含的整个代码在另一端的转储都是不可维护的,因为它显然会导致代码重复的混乱。

内联通过让您将函数声明为 inline (至少在C ++中)来解决性能和可维护性问题,这样当您调用该函数时 - 而不是你的应用程序在运行时跳转 - 每次调用给定函数时,内联函数中的代码都会在编译时注入。

这样做的缺点是 - 如果你内联很多次调用的函数 - 程序的大小可能会显着增加(最佳实践建议只在小函数上执行)

答案 1 :(得分:12)

http://en.wikipedia.org/wiki/Inlining

在计算,内联扩展或内联中,是一种编译器优化,它将函数调用站点替换为被调用者的主体。此优化可以在运行时改善时间和空间使用,但可能会增加最终程序的大小。

答案 2 :(得分:7)

作为Java开发人员,您通常不必担心方法内联。 Java的即时编译器可以并且将在大多数有意义的地方自动执行。

像eclipse这样的IDE可以有一个功能,允许你在源代码级别内联方法 - 从不这样做是为了提高性能,只为了代码可读性(例如,当你意识到方法只调用一个其他方法没有添加任何有用的东西)。

答案 3 :(得分:2)

正如其他答案中已经提到的,内联带有成本。通常这被认为是小的,但是当实际测量时你可能会感到惊讶并且知道它可能比你获得的更大(所以what other people say是真的:除非你已经测量过,否则不要优化。)

值得注意的是,在Linux内核中,他们不久前开始非内联最初内联函数,因为成本太高(较大的函数消耗了更多的cpu内存缓存,并且导致的缓存未命中比仅仅更昂贵调用打算内联的函数。有关详细信息,请参阅doc/Documentation/process/coding-style.rst中的“第15章:内联疾病”。

答案 4 :(得分:1)

Norman Maurer 在他的blog JVM和JIT内联功能中进行了解释

  

内联是一种基本上只将一个方法“内联”到另一个方法中的技术,因此摆脱了方法调用。 JIT自动检测“热”方法并尝试为您内联。如果方法执行X次以上,则该方法被视为“热”方法,其中X是可以使用启动Java时的JVM标志(默认值为10000)。之所以需要这样做,是因为由于产生了大量的字节码,所以内联所有方法比其他方法造成的危害更大。此外,当优化在后来的状态下是错误的时,JIT可以“还原”先前的内联代码。请记住,JIT代表“及时”,因此在执行代码时进行优化(包括内联和其他操作)。

也有警告

  

但是,即使JVM认为某个方法“很热”,它也可能不会内联。但为什么?最可能的原因之一是内嵌只是很大。

您可以在Eva Andreasson's Java World Post找到一个非常简单的代码示例来内联Java代码。您可以在下面找到帖子的相关部分。

  

许多优化尝试消除机器级别的跳转指令(例如,用于x86架构的JMP)。跳转指令更改指令指针寄存器,从而传输执行流程。相对于其他ASSEMBLY指令而言,这是一项昂贵的操作,这就是为什么要减少或消除这种常见目标的原因。 针对此的非常有用且广为人知的优化称为内联。由于跳转的开销很大,因此可以将许多对具有不同入口地址的小型方法的频繁调用内联到调用函数中,这很有帮助。清单3至5中的Java代码体现了内联的好处。

列出3.调用者方法

int whenToEvaluateZing(int y) {
   return daysLeft(y) + daysLeft(0) + daysLeft(y+1);
}

清单4.调用的方法

int daysLeft(int x){
   if (x == 0)
      return 0;
   else
      return x - 1;
}

清单5.内联方法

int whenToEvaluateZing(int y){
   int temp = 0;

   if(y == 0) temp += 0; else temp += y - 1;
   if(0 == 0) temp += 0; else temp += 0 - 1;
   if(y+1 == 0) temp += 0; else temp += (y + 1) - 1;

   return temp; 
}
  

在清单3至清单5中,调用方法对a   小方法,我们假设在此示例中,该方法更多   对于内联而言,比跳到三倍更有帮助。

     

内联调用一个方法可能没有多大区别   很少,但是内联了一种经常使用的所谓“热”方法   调用可能意味着性能上的巨大差异。也内联   通常会为进一步的优化让路,如清单6所示。

清单6.内联后,可以应用更多优化

int whenToEvaluateZing(int y){
   if(y == 0) return y;
   else if (y == -1) return y - 1;
   else return y + y - 1;
}

答案 5 :(得分:0)

基本上,在C / C ++中,编译器可以内联函数,这意味着代码不会进行函数调用来执行该操作,而是将代码添加到调用函数的块中,因此它就好像从来没有是一个单独的函数调用。

这将详细介绍: http://www.codersource.net/cpp_tutorial_inline_functions.html

答案 6 :(得分:0)

内联是指编译时优化,其中一小段代码函数将被注入调用函数,而不需要单独调用。

答案 7 :(得分:0)

编译器优化答案是正确的。但是还有另一种用法 - 在refactoring中,内联是指用方法体替换方法调用然后删除方法。见Inline Method。有类似的重构,例如Inline Class

编辑:请注意,重构是手动完成或使用工具完成的;在任何一种情况下,它都涉及更改源代码。

答案 8 :(得分:0)

内联函数通常用于C ++头文件而不是Java。 C ++头文件通常不包含已实现的代码,并且被视为同名cpp文件的接口,该文件通常包含已实现的代码。在头文件中包含内联函数是合法的,通常是一个小的轻量级函数。内联函数确实需要付出代价,因此它们不应该是大量内存密集型操作。对于小型例程,性能损失很小,为方便起见,它们更常用。

答案 9 :(得分:-1)

在该讨论中,如果允许JIT(即时)编译器允许基于时间的增强,Jon Skeet在运行时提到了客户端jvm(hotspot)v Server jvm的性能改进。这就是Java中的“如何完成”。

最初,未被许多地方调用的小部分代码将由编译器“内联”,这意味着所谓的单例将直接放在指令指针代码路径中,执行函数分支并返回成本更多的处理器能力,而不仅仅是展开循环或函数调用并将指令“放在那里”

今天,Singleton是多页讨论和循环展开的主题,以及类似内联的东西在某种程度上已从其原始上下文中删除。你可以阅读Dov Bulka关于此事的非常明智的工作,以便让C / C ++接受这个问题。对于Java,在java.util中研究它丰富的lib比研究内联和深度编译器问题更能满足你的需求 - 你可以在数据结构上陷入根深蒂固的陷入困境的内部战争中,这可以掩盖对16位代码的调用,以及你的学习曲线没有尽头。

你可以在Java中做instanceof,它类似于一个vf表(请不要热情的人),但是当你用强类型语言写的时候想想它 - 现在将用一种字符串可以失控的语言编写很容易在没有业务的地方闲逛。我最近尝试编写用Java构建Image的代码,用C代码完成。我很快就发现自己正在查看oxr表中的强加密 - 这与我编写的代码无关。

你如何在C / C ++中编写一个字符串类,它对32字节以下的字符串有一个小缓冲区并捕获指针以便它们只对字符串进行操作?

不要试图取笑你或任何东西,它只是一个非常好的开始而不是内联和编译科学的地方。