Lambdas and implicit references to the instance of the enclosing class

The “Show Kotlin Bytecode” view is very helpful for answering such questions, if you can read bytecode at least (it’s not that hard). You can open it in the tools menu.

Like in Java, what happens in Kotlin varies in different cases.

  • If the lambda is passed to an inline function and isn’t marked noinline, then the whole thing boils away and no additional classes or objects are created.
  • If the lambda doesn’t capture, then it’ll be emitted as a singleton class whose instance is reused again and again (one class+one object allocation).
  • If the lambda captures then a new object is created each time the lambda is used.

Thus it is similar behaviour to Java except for the inlining case where it’s even cheaper. This efficient approach to encoding lambdas is one reason why functional programming in Kotlin is more attractive than in Java.

Note, however, the following caveat. Currently the Kotlin compiler does not use the Java 8 invokedynamic infrastructure for spinning lambda classes at runtime. Thus whilst Kotlin lambdas are comparable in terms of runtime performance to Java, they take up more space on disk and require more class files in the shipped JARs which in turn imposes a small load time penalty, as it’s faster to create code entirely in memory on-demand than load and decompress from a ZIP file. The Kotlin team plan to start emitting Java 8 style bytecode in future.

Switching to Java 8’s LambdaMetaFactories via invokedynamic unlocks other benefits: it takes less RAM and creates less lock contention inside the JVM itself. A future version of HotSpot is planned to continue to improve the efficiency of lambdas:

http://openjdk.java.net/jeps/8158765

3 Likes