java for循环的效率

java for循环的效率,java,memory-management,loops,for-loop,Java,Memory Management,Loops,For Loop,作为这个问题的增编 我有一个简单的问题。增强的for循环是否有更大的内存占用空间,或者它们都编译为相同的结构,使它们的内存占用空间相同,从而使(对象o:collection){…}对于只读操作总是更好 我问这个问题的原因是,在我正在工作的模拟器中,每一帧(60秒)我都在对数组中的数千项运行操作,例如绘制面、光线跟踪等。循环 for(Object o : collection) { o.doSomething(); } 看起来它可能会制作一个集合的内存副本(我记得我以前读过它),这在大多

作为这个问题的增编

我有一个简单的问题。增强的for循环是否有更大的内存占用空间,或者它们都编译为相同的结构,使它们的内存占用空间相同,从而使(对象o:collection){…}对于只读操作总是更好

我问这个问题的原因是,在我正在工作的模拟器中,每一帧(60秒)我都在对数组中的数千项运行操作,例如绘制面、光线跟踪等。循环

for(Object o : collection) {
   o.doSomething(); 
}
看起来它可能会制作一个集合的内存副本(我记得我以前读过它),这在大多数情况下都是可以的,但如果每秒执行30000次光线跟踪60次,则不会

另一方面,很明显,循环

count = collection.size();
for(i = 0; i < count; i++) {
   collection[i].doSomething();
}
count=collection.size();
对于(i=0;i
每件事都是通过参考来完成的,而且占用的空间相对较小,尽管它很难阅读(尽管老实说,不多)

有什么想法吗,伙计们


(注意:读循环的难度的影响只有在你有好几层的时候才明显-对于单层来说,增益是非常小的。我是根据经验说的…
collection[I].property.subcollection[j].row[k].col[l].prop.subtable[m]
会成为一个思维破坏者,特别是当其中一些需要转换时:
((Type3)((Type2)((Type1)collection[i]).property.subcollection[j].row[k].col[l].prop).子表[m]
例如。)

如果您有一个使用以下模式的ArrayList,则可以进行微优化

for(int i=0, len=list.size(); i < len; i++)
for(int i=0,len=list.size();i
您保存的内存约为16-24字节,因为for-each循环将始终创建一个迭代器

(60/秒)我正在对数组中的数千个项目运行操作,例如要绘制的面、要光线跟踪的面、

每秒60000次,您不太可能注意到差异,尤其是在您对每个项目进行相对重要的工作时

看起来它可能会生成集合的内存副本


但事实并非如此,这就是为什么在循环列表时更改列表会得到ConcurrentModificationException。解决方法之一是复制一份。很难说JIT将如何优化代码(哪种Java实现、哪种操作系统等)。这里的要点是for each语法编译为与使用迭代器语法相同的字节码。请参阅和。使用迭代器语法的主要原因是在迭代过程中删除项。请注意,接口上的remove方法是可选的

我自己制作了一些简单的示例来查看字节码:

对于数组的每次迭代

// compiled .class file is 585 bytes
public class ForEachLoop {
  public static void main(String[] args) {
    for(String s : args){
      System.out.println(s);
    }
  }
}

// byte code for main method
public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=5, Args_size=1
   0:   aload_0
   1:   dup
   2:   astore  4
   4:   arraylength
   5:   istore_3
   6:   iconst_0
   7:   istore_2
   8:   goto    26
   11:  aload   4
   13:  iload_2
   14:  aaload
   15:  astore_1
   16:  getstatic   #16; //Field java/lang/System.out:Ljava/io/PrintStream;
   19:  aload_1
   20:  invokevirtual   #22; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   23:  iinc    2, 1
   26:  iload_2
   27:  iload_3
   28:  if_icmplt   11
   31:  return
  LineNumberTable: 
   line 4: 0
   line 5: 16
   line 4: 23
   line 7: 31

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      32      0    args       [Ljava/lang/String;
   16      7      1    s       Ljava/lang/String;
数组索引循环

// compiled .class file is 554 bytes
public class ArrayLoop {
  public static void main(String[] args) {
    for (int i = 0; i < args.length; i++) {
      System.out.println(args[i]);
    }
  }
}

// byte code for main method
public static void main(java.lang.String[]);
  Code:
   Stack=3, Locals=2, Args_size=1
   0:   iconst_0
   1:   istore_1
   2:   goto    17
   5:   getstatic   #16; //Field java/lang/System.out:Ljava/io/PrintStream;
   8:   aload_0
   9:   iload_1
   10:  aaload
   11:  invokevirtual   #22; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  iinc    1, 1
   17:  iload_1
   18:  aload_0
   19:  arraylength
   20:  if_icmplt   5
   23:  return
  LineNumberTable: 
   line 4: 0
   line 5: 5
   line 4: 14
   line 7: 23

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      24      0    args       [Ljava/lang/String;
   2      21      1    i       I
//编译的.class文件为554字节
公共类ArrayLop{
公共静态void main(字符串[]args){
对于(int i=0;i

我们可以看到,数组迭代字节码更紧凑(精确地说是31个字节).

至少我可以告诉你,第二个循环实际上允许你在不破坏迭代器(又称ConcurrentModificationException地狱)的情况下更改列表。这确实很有用。你的第二个循环不会编译。
collection
是数组还是
collection
?Enhanced for循环将变成迭代器基因此,它的开销可能稍高一些。但是,JIT可以消除这种开销。@RiverC-除非您只使用
Iterator.remove()
…@RiverC:我只是说数组的foreach循环编译为不同的字节码,而不是
Iterable的字节码。我想这与你的问题有关……60000多个操作不在同一个列表中(一个简单的60000个列表)但在某些情况下,在许多多维列表上。这只是为了澄清。好吧,如果你每秒迭代60000个列表,那么使用随机访问可能比使用for each更好,因为它每次都会保存一个迭代器。迭代器每次都会被销毁吗?或者集合(如果不是数组)会重用它的迭代器吗在某些情况下,我使用数组是因为它们的内存开销较小,即地图中的数据点可能会将集合数据附加到每个点,因此我使用数组来避免数千个集合。@RiverC每次请求迭代器时,您都会得到一个新的迭代器。这一点很重要,因为它保留了您个人当前itera的状态在你的更新中,数组的情况如何(我有时使用数组,因为它们占用的内存很小)?很酷!所以你在正常的for循环中占用的程序内存更少。