【问题标题】:Java loop questionsJava循环问题
【发布时间】:2012-08-07 21:02:17
【问题描述】:
Object[] objs = new Object[5];
for (int i = 0; i < 5; ++i) {
    int j = i + 1;
    Object obj = objs[i];
}

我对上述循环有两个问题:

  1. 是为每个循环迭代创建j 变量和obj 引用还是创建一次然后只重新分配值?
  2. ++i 而不是 i++ 作为单个指令来增加值是否有任何性能优势?

【问题讨论】:

  • 如果您使用 Hotspot VM 运行,它很可能会优化 int 分配以及对象引用。
  • 前缀或后缀(++ii++)仅在您将它们放入作业时才重要(虽然没有性能差异)。

标签: java for-loop


【解决方案1】:

是为每个循环迭代创建 j 变量和 obj 引用,还是创建一次然后只重新分配值?

每次都声明和创建

将 ++i 而不是 i++ 作为单个指令来增加值有什么性能优势吗?

不是真的。

【讨论】:

  • 那么你认为将下面的循环写成 Object[] objs = new Object[5]; 是一种很好的风格吗?诠释 j;对象对象;对于 (int i = 0; i
  • 没有。一点也不。变量应该在尽可能窄的范围内声明。
  • 不,因为为他们保留位置是一种廉价的操作,而 IMO,编写正确清晰的代码更为重要。
  • @OneMoreVladimir 您不会看到性能方面的差异。
  • 请记住,声明变量与实例化对象不同。将“int j”和“Object obj”声明放在循环之外不会节省任何内存或 CPU 周期,相反,对象会在内存中停留更长时间,直到块结束,而不是直到 for 循环结束。
【解决方案2】:

j 变量和 obj 引用是为每次循环迭代创建的,还是创建一次然后只重新分配值?

每次循环时,都会创建一个新的 int,但 obj 只是对现有对象的引用,因此不会触发对象创建。无论如何,JVM 很可能会为您优化。

将 ++i 而不是 i++ 作为单个指令来增加值有什么性能优势吗?

很可能没有什么值得注意的地方,JVM 可能会再次更改您的代码。

底线:使用更具可读性的任何内容,并将变量的范围限制在使用它们的位置。

实际上,JVM 可能会将你的代码更改为这样,因为你没有在循环中使用局部变量:

Object[] objs = new Object[5];
//for (int i = 0; i < 5; ++i) {
//    int j = i + 1;
//    Object obj = objs[i];
//}

【讨论】:

  • @onemorevladimir:我打算在另一个答案中发表评论,但这个答案直截了当:JVM 将优化您的代码,您甚至无法比较放置变量的结果等,在循环内部或外部。要进行测试,您需要在循环中实际使用这些变量,以便 JVM 可以将它们释放出来。
【解决方案3】:

我已经比较了代码部分的两个字节码。我没有发现什么特别的。唯一不同的是,在第一个示例代码部分中定义了 4 个局部变量,但在第二个示例代码部分中定义了 5 个局部变量。然而,类似的操作码被执行。由于局部变量名称不同,因此执行不同的操作码。我的意思是在第一个示例中“i 被定义为 local-variable-2”,在第二个示例中“i 被定义为 local-variable-4”。

但是通过 JVM 工具监控代码执行可以提供额外的信息。由于 Java 是一个平台,JVM 可能会优化代码执行,因此我们可能无法通过查看 java 源代码或 java 字节码来确定。

    Object[] objs = new Object[5];  
    for (int i = 0; i < 5; ++i) {  
       int j = i + 1;  
       Object  obj = objs[i];  
    }  

 local-variable-0=this
 local-variable-1=objs
 local-variable-2=i
 local-variable-3=j

  stack=2, locals=5, args_size=1 
 0: aload_0 
 1: invokespecial #8                  // Method java/lang/Object."<init>":()V 
 4: iconst_5 
 5: anewarray     #3                  // class java/lang/Object 
 8: astore_1 #store created object referance to local value-1 (objs)
 9: iconst_0 #push 0 on stack
10: istore_2  # local-value-2(i) assigned 0
11: goto          26 
14: iload_2  #load localvalue 2(i)
15: iconst_1 # ++i operation
16: iadd  #i+1
17: istore_3 #assign i+1 into local-variable-3(j)
18: aload_1 # push object in local varable 1 (objs) onto the stack
19: iload_2 # push integer in local variable 2 (i) onto the stack
20: aaload  # retrieve entry
21: astore        4 # push value on stack into local-variable-4 (obj)
23: iinc          2, 1 # local-variable-2(i)++
26: iload_2 
27: iconst_5 
28: if_icmplt     14 for(if i==5)
31: return 

 **************************************************************************
  Object[] objs = new Object[5];  
    int j; 
    Object obj; 
    for (int i = 0; i < 5; ++i) {  
        j = i + 1;  
        obj = objs[i];  
    }  

  local-variable-0=this
 local-variable-1=objs
 local-variable-2=j
 local-variable-3=obj
 local-variable-4=i

  stack=2, locals=5, args_size=1 
     0: aload_0 
     1: invokespecial #8                  // Method java/lang/Object."<init>":()V 
     4: iconst_5 
     5: anewarray     #3                  // class java/lang/Object 
     8: astore_1 #store created object referance to local value-1 (objs)
     9: iconst_0 #push zero on to the stack
    10: istore        4 # local variable-4(i) is assigned zero
    12: goto          28 
    15: iload         4 
    17: iconst_1 
    18: iadd  #i+1
    19: istore_2  #j is set 
    20: aload_1  #load objs
    21: iload         4 #load i
    23: aaload 
    24: astore_3  #obj=objs[i]
    25: iinc          4, 1 # i++
    28: iload         4 
    30: iconst_5 
    31: if_icmplt     15 # if i==5
    34: return 

【讨论】:

  • 我正在准备我的 cmets,我将很快更新我的答案。
【解决方案4】:

是的!

这样做:

Object[] objs = new Object[5]; 
int j = 0;
Object obj = new Object();
for (int i = 0; i < 5; ++i) {   
   j = i + 1;   
   obj = objs[i]; 
} 

【讨论】:

  • 您的方法实际上创建了一个他没有创建的新对象。
【解决方案5】:

是的,他们每次都创建,前缀或后缀 ++ 并不重要。

【讨论】:

    【解决方案6】:

    j 变量和 obj 引用是为每次循环迭代创建的,还是创建一次然后只重新分配值?

    理论上是的。在实践中优化代码这不会发生。但是,在您的情况下,可能不会优化 5 个(或少于 10,000 个)的循环,因为它的性能可能并不重要。

    将 ++i 而不是 i++ 作为单个指令来增加值有什么性能优势吗?

    对于优化的代码,它们在这里是相同的。对于未优化的代码,差异不大。

    【讨论】:

      【解决方案7】:

      我会尽力回答你的问题....

      Are the j variable and obj reference created for every loop iteration or they are createdonce and then only reassigned the values?

      int j每次都创建Object Reference Variable obj 也是每次在循环内创建,但不是@ 987654325@.

      Is there any perfomance benefit of putting ++i instead of i++ as a single instruction toincrement the value?

      在这种情况下,没有分配j's value没关系。

      【讨论】:

        猜你喜欢
        • 2013-04-07
        • 2011-07-03
        • 1970-01-01
        • 2019-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多