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

推荐答案

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

for (i in 0..count - 1)

所有其他形式的分配结果要么是Range,要么是Iterator.不幸的是,你甚至不能定义一个有效的反向循环.

Kotlin相关问答推荐

两个LocalDateTime之间的Kotlin差异

try 一次性插入多条记录时,JOOQ连接为空错误

Lets plot Kotlin中的多轴比例

将 Integer 转换为 Unit 编译成功

内容更改后的 var 重新计算

如何为 Kotlin 中的每个循环设置以避免越界异常

Kotlin 具体类从抽象类和接口扩展而来,接口使用抽象类中实现的方法

无法解决:androidx.lifecycle:lifecycle-viewmodel-ktx:1.1.1

Kotlin - 覆盖方法中的 IllegalArgumentException

Android Kotlin StringRes 数量String

防止导航到同一个片段

Kotlin:什么是 kotlin.String!类型

kotlin RecyclerView分页

添加抽象的私有getter和公共setter的正确方法是什么?

空对象引用上的 TransitionSet ArrayList.size()

Jetpack Compose-居中文本

如何让数据类在Kotlin中实现接口/扩展超类属性?

如何在Kotlin中使方法param可变?

Dagger +Kotlin 不注入

Kotlin 的数据类 == C# 的 struct ?