I'm working on a game written in Kotlin and was looking into improving GC churn. One of the major sources of churn are for-loops called in the main game/rendering loops that result in the allocation of iterators.
Turning to the documentation, I found this paragraph:
A for loop over an array is compiled to an index-based loop that does not create an iterator object.
如果要通过索引遍历数组或列表,可以这样做:
for (i in array.indices)
print(array[i])
Note that this “iteration through a range” is compiled down to optimal implementation with no extra objects created.
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
对象来备份循环中的边界判断.这是一个"没有创建额外对象"的"最佳实现",还是我遗漏了什么?
UPDATE: So, after toying around a bit more and looking at the answers, the following appears to be true for Kotlin 1.0.2:
Arrays:
-
for (i in array.indices)
:范围分配 -
for (i in 0..array.size)
: no allocation -
for (el in array)
:没有分配 -
array.forEach
:不分配
Collections:
-
for (i in coll.indices)
范围分配 -
for (i in 0..coll.size)
: no allocation -
for (el in coll)
:迭代器分配 -
coll.forEach
: iterator allocation