【问题标题】:Java - Will inlining code have benefits?Java - 内联代码有好处吗?
【发布时间】:2016-03-30 11:20:35
【问题描述】:

我做了一些研究,但我大多看到 c++ 的答案。我最接近的是this。我也看到了this page,但它并没有真正解释什么。

如果我使用第二段代码有什么好处吗?会有明显的性能差异吗?内存呢?如果重复执行怎么办?

现在我有这个功能。我确信这样做的好处是代码可读性:

private static Bitmap resize(Bitmap image, int maxWidth) {
    float widthReducePercentage = ((float) maxWidth / image.getWidth());
    int scaledHeight = Math.round(image.getHeight() * widthReducePercentage);

    return Bitmap.createScaledBitmap(image, maxWidth, scaledHeight, true);
}

现在,我有了第二个 sn-p 代码:

private static Bitmap resize(Bitmap image, int maxWidth) {
    return Bitmap.createScaledBitmap(image, maxWidth, Math.round(image.getHeight() * (float) maxWidth / image.getWidth()), true);
}

一个更简单的例子是:

for(;;) {
    String foo = "hello";
    Console.print(foo + "world");
}

for(;;) {
    Console.print("hello" + "world");
}

【问题讨论】:

  • 我相信编译器无论如何都会优化东西,因此您的测试对示例可能会执行类似的操作。无论如何,内联可以让代码更容易阅读。
  • 对于您提供的示例,性能不会有任何差异。甚至不要为这样的“优化”而烦恼,只要做最好的事情。
  • @LouisWasserman Roger 那
  • 第二个优化示例:Console.print("hello world"); 这节省了字符串连接(在每次迭代中),这很昂贵。

标签: java android performance memory-management inline


【解决方案1】:

首先:这不是“内联”的意思。见:What is inlining?

第二:不,性能上不会有任何可衡量的差异。在您的两个代码示例中,两个版本的编译代码很可能是相同的。

【讨论】:

  • Java 字节码会有所不同,因为不会消除局部变量(它们可用于调试)。 JIT 和大概 Dalvik 编译器会删除它们。
  • 贴出这个答案后,我做了一个简单的实验,类似于LIProf。而且编译出来的文件确实不一样。除了我使用了-g:none 标志,所以不应该有任何调试符号。所以我想这比我想象的要复杂一些。
【解决方案2】:

我定义了两个简单的类Test1Test2并编译了它们。

public class Test1{
    public String f(){
        String s = "Hello";
        String t = "There";
        return s + t;
    }
}

public class Test2{
    public String f(){
        return "Hello" + "There";
    }   
}

令我惊讶的是,.class 文件的大小不同。

-rw-r--r--  1 csckzp  staff  426 Dec 23 19:43 Test1.class
-rw-r--r--  1 csckzp  staff  268 Dec 23 19:43 Test2.class

也许我不应该感到惊讶,因为一些符号信息与代码一起存储。我通过在线反编译器运行 .class 文件。 Test1 的重构方式几乎与输入的方式相同。另一方面,Test2 以这种方式反编译:

public class Test2 {
    public String f() {
        return "HelloThere";
    }
}

这里清楚地显示了编译器的优化。在 Java 中,非紧凑代码可能会受到一点惩罚。

【讨论】:

  • 我并不感到惊讶;字节码编译器做了非常最小的优化。它们的等价性将在运行时得到证明。
  • 编译器会尝试消除其结果可以在编译时确定的操作。这就是为什么“Hello”+“There”变成了“HelloThere”。
【解决方案3】:

他们都是一样的。前者只是让事情比后者更清楚。

在某些情况下,例如下面的块,单行线很有用。

public boolean isEmpty() {
   return getCount() != 0;
}

如果您想让它更易于阅读,尤其是在涉及方程式时,请选择variable。单行使其简单而简短,但适用于简短的逻辑。

这是我个人的看法。

【讨论】:

    【解决方案4】:

    虽然局部变量在转换为字节码的过程中仍然存在,但它们不太可能在及时编译中存在。此外,即使存在局部变量,它们也不会显着影响该方法的性能,因为重新缩放位图比存储或检索局部变量要昂贵几个数量级。

    关于字符串连接的第二个示例突出了该规则的一个小例外,因为局部变量的存在可能会抑制常量字符串连接的编译时评估。但是,这不太可能对程序的运行时间产生重大影响,因为您可能不会经常连接常量字符串。

    一般来说,内联局部变量对运行时性能的影响是很难衡量的,更不用说显着了。因此,通过使代码易于阅读和推理,您可以更好地花时间优化程序员的性能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-18
      • 2020-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多