数组/列表迭代没有额外的对象分配
我正在编写一个用Kotlin编写的游戏,并正在研究改进GC流失。 流失的主要来源之一是在主游戏/渲染循环中调用for循环,从而导致迭代器的分配。
谈到文档,我发现这一段:
对数组的for循环编译为基于索引的循环,不会创建迭代器对象。
如果你想通过一个索引来遍历数组或列表,你可以这样做:
for (i in array.indices) print(array[i])
请注意,这个“通过范围迭代”被编译为最佳实现,没有创建额外的对象。
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]) } }
根据上面的引用,这不应该导致任何对象分配,而是被编译成一个良好的旧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
这看起来好像调用一个名为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
:迭代器分配
据我所知,定义for
循环的唯一无分配方式是
for (i in 0..count - 1)
所有其他形式导致Range
分配或Iterator
分配。 不幸的是,你甚至无法定义一个有效for
循环反向。
要迭代数组而不分配额外的对象,可以使用以下方法之一。
-
for
-loop
for (e in arr) { println(e) }
-
forEach
扩展
arr.forEach { println(it) }
-
forEachIndexed
扩展名,如果你需要知道每个元素的索引
arr.forEachIndexed { index, e -> println("$e at $index") }