Array/List iteration без дополнительных распределений объектов
Я работаю над игрой, написанной в Котлине, и изучал улучшение оттока GC. Один из основных источников оттока - это петли, называемые в основных циклах игры/рендеринга, которые приводят к распределению итераторов.
Переходя к документации, я нашел этот абзац:
А для цикла по массиву компилируется в цикл, основанный на индексе, который не создает объект итератора.
Если вы хотите итерации по массиву или списку с индексом, вы можете сделать это следующим образом:
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])
}
}
Согласно приведенной выше цитате, это не должно приводить к назначению каких-либо объектов, но скомпилировать их до старого старого стиля pre-Java-5 для цикла. Однако я получил следующее:
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:
Итак, после многого другого и поиска ответов, для 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
: распределение итератора
Ответы
Ответ 1
Насколько я знаю, единственный способ определения без привязки for
:
for (i in 0..count - 1)
Все остальные формы приводят либо к распределению Range
, либо к распределению Iterator
. К сожалению, вы даже не можете определить эффективный обратный цикл for
.
Ответ 2
Для итерации массива без выделения дополнительных объектов вы можете использовать один из следующих способов.
for (e in arr) {
println(e)
}
-
forEach
расширение
arr.forEach {
println(it)
}
-
forEachIndexed
расширение, если вам нужно знать индекс каждого элемента
arr.forEachIndexed { index, e ->
println("$e at $index")
}