没有额外对象分配的数组/列表迭代

Mat*_*ias 34 kotlin

我正在研究用Kotlin编写的游戏,并正在研究改进GC流失.流失的主要来源之一是在主游戏/渲染循环中调用的for循环,导致迭代器的分配.

谈到文档,我发现了这一段:

数组上的for循环被编译为基于索引的循环,该循环不会创建迭代器对象.

如果要迭代数组或带索引的列表,可以这样做:

for (i in array.indices)
  print(array[i])
Run Code Online (Sandbox Code Playgroud)

请注意,这种"通过范围的迭代"被编译为最佳实现,而不创建额外的对象.

https://kotlinlang.org/docs/reference/control-flow.html#for-loops

这是真的吗?为了验证,我采用了这个简单的Kotlin程序并检查了生成的字节代码:

fun main(args: Array<String>) {
    val arr = arrayOf(1, 2, 3)
    for (i in arr.indices) {
        println(arr[i])
    }
}
Run Code Online (Sandbox Code Playgroud)

根据上面的引用,这不应该导致分配任何对象,而是编译成一个很好的旧的Java-5前样式for循环.但是,我得到的是这样的:

      41: aload_1
      42: checkcast     #23                 // class "[Ljava/lang/Object;"
      45: invokestatic  #31                 // Method kotlin/collections/ArraysKt.getIndices:([Ljava/lang/Object;)Lkotlin/ranges/IntRange;
      48: dup
      49: invokevirtual #37                 // Method kotlin/ranges/IntRange.getFirst:()I
      52: istore_2
      53: invokevirtual #40                 // Method kotlin/ranges/IntRange.getLast:()I
      56: istore_3
      57: iload_2
      58: iload_3
      59: if_icmpgt     93
Run Code Online (Sandbox Code Playgroud)

这看起来好像调用了一个调用的方法,该方法getIndices分配一个临时IntRange对象来备份此循环中的边界检查.这是一个"最佳实现","没有创建额外的对象",或者我错过了什么?

更新: 所以,经过多一点玩弄并查看答案之后,Kotlin 1.0.2似乎也是如此:

阵列:

  • for (i in array.indices):范围分配
  • for (i in 0..array.size):没有分配
  • for (el in array):没有分配
  • array.forEach:没有分配

类别:

  • for (i in coll.indices) 范围分配
  • for (i in 0..coll.size):没有分配
  • for (el in coll):迭代器分配
  • coll.forEach:迭代器分配

Ily*_*lya 33

要在不分配额外对象的情况下迭代数组,可以使用以下方法之一.

  1. for-环
    for (e in arr) {
        println(e)
    }
Run Code Online (Sandbox Code Playgroud)
  1. forEach 延期
    arr.forEach {
        println(it)
    }
Run Code Online (Sandbox Code Playgroud)
  1. forEachIndexed 扩展,如果你需要知道每个元素的索引
    arr.forEachIndexed { index, e ->
        println("$e at $index")
    }
Run Code Online (Sandbox Code Playgroud)

  • 现在这很有趣.我假设所有这些都会导致迭代器的分配 - 但它们不会,至少在迭代对象是数组的情况下不会.它们用于列表和其他集合类型.感谢您指出了这一点! (2认同)

Mic*_*ael 16

据我所知,定义for循环的唯一无分配方法是

for (i in 0..count - 1)
Run Code Online (Sandbox Code Playgroud)

所有其他形式都会导致Range分配或Iterator分配.不幸的是,你甚至无法定义有效的反向for循环.

  • 这是一个纯粹的编译器优化,我想将来还会有更多.https://youtrack.jetbrains.com/issue/KT-11173 (3认同)