【问题标题】:Any difference in the performance of these two Java segments?这两个 Java 段的性能有什么不同吗?
【发布时间】:2010-07-29 20:29:52
【问题描述】:

我很想知道这两个 Java 方法调用中的任何一个在处理器时间、内存分配和/或垃圾回收方面的行为是否完全不同。

SomeObject myObj = new SomeObject();
myObj.doSomething();

对比

new SomeObject().doSomething();

【问题讨论】:

  • 我希望你不要经常创建一个对象只是为了调用它的单个方法。或者担心这样的表现。
  • @Tom:那为什么不好?如果他只需要执行一种方法,然后他就完成了,那么,好吧,这就是他需要做的一切。比如,“new Logger().write("Panic!Abort!我们要倒下了!");”我们没有使用记录器 agan。至于性能差异,对于一个电话,我敢肯定这是微不足道的。但这些东西加起来。节省一纳秒就是赚一纳秒。
  • 不经常。它来自于在 Android 应用程序中生成一个新线程。
  • @Jay 纳秒富,毫秒穷。
  • 我不能等到我有足够的代表来创建自己的标签并将其粘贴到其他人的帖子上 :) 说真的,我认为差异很小 - 我从不担心。我什至没有将其更改为“更快”的方式。我只是好奇。

标签: java micro-optimization


【解决方案1】:

查看生成的字节码:

// code 1
new SomeObject().doSomething();

// bytecode 1
   0:   new #2; //class SomeObject
   3:   dup
   4:   invokespecial   #3; //Method SomeObject."<init>":()V
   7:   invokevirtual   #4; //Method SomeObject.doSomething:()V
   10:  return

你可以清楚的看到这个还有两条指令:

// code 2
SomeObject myObj = new SomeObject();
myObj.doSomething();

// bytecode 2
   0:   new #2; //class SomeObject
   3:   dup
   4:   invokespecial   #3; //Method SomeObject."<init>":()V
   7:   astore_1
   8:   aload_1
   9:   invokevirtual   #4; //Method SomeObject.doSomething:()V
   12:  return

这些指令看起来非常多余且易于优化。我敢打赌 JIT 编译器会在需要时处理它们。

【讨论】:

  • 这与我预期的差不多。感谢您比我懒惰并发布字节码!
【解决方案2】:

差异正好是 2 个 JVM 字节码,它转换为 1 个额外的机器指令,JIT 可能会优化掉这些指令(如果您不对变量做任何其他事情)。

【讨论】:

  • 如果考虑明智的话,天真的机器代码翻译通常会引入两条指令(存储到本地帧,然后加载相同的) - 与字节码相同。
  • 不,编译器可以立即在寄存器或堆栈中重用该值(暂时忽略 volatile vars)。由于语义,javac 将放置 2 个指令(一个存储,一个加载)。
【解决方案3】:

没有。

【讨论】:

  • 哈 - 我期待这个。
【解决方案4】:

假设 myObj 没有用于其他任何事情,正如我从您问题的性质推断的那样,您应该看不出有什么区别。无论哪种方式,您唯一应该担心这样的开销的情况是,如果这段代码处于某个循环中,并且一遍又一遍地执行它,令人作呕。如果是这种情况,Java 的 JIT 优化应该会很好地照顾你,你应该看不出有什么区别。我更喜欢按照您的第二个示例的方式编写此代码,但这只是我。

【讨论】:

  • 我更喜欢变体 1,因为它使调试更容易。每一行都有一个方法调用,因此您可以为每种方法决定是单步执行还是跳过它。这样,您还可以检查算法的中间结果以检查它们是否具有预期值。当调用方法会产生不需要的副作用时,这一点尤其重要。
【解决方案5】:

虽然生成的字节码可能不同,但我认为这应该是 jit 编译器更容易优化的事情之一。根据它的实际作用,甚至可以完全优化对象创建。

【讨论】:

    【解决方案6】:

    两者之间的唯一区别是,只要不清除myObj 引用并且具有path to root 的对象的一部分将不会被垃圾回收。

    【讨论】:

      【解决方案7】:

      第一个示例的效率会稍低一些。在第一个示例中,对象引用将一直保留到函数或封闭块结束。在第二个示例中,一旦调用完成,对象引用将可用于垃圾回收。当然,它可能实际上并没有被垃圾回收。

      我没有检查生成的字节码。 Java 持有引用的方式可能有所不同,但无论哪种情况,我都怀疑它是微不足道的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多