Switch Theme

Kotlin’s Performance

kotlin

5/14/2025

thumbnail

9 min. read

Kotlin is a modern programming language that has gained popularity for its concise syntax and interoperability with Java. As I’ve been exploring Kotlin, it’s come to become my favorite programming language. I built the benchmarks application in Kotlin, and included Kotlin as one of the languages it compares against. In this post, I want to share my thoughts on Kotlin’s performance and how it compares to other languages.

Performance Overview

Kotlin JVM ranks last. And it’s not close.

/assets/img/kotlin-performance/1.png

At first, I thought this was a fault on my part. Maybe I was measuring the wrong thing, or maybe I was using the wrong libraries. But after some investigation, I found that Kotlin’s performance is consistently lower than the rest of the languages in the benchmarks. I even decided to turn on compiler optimizations for this language at one point, and it still didn’t help.

Let’s take a look at how the app actually works. It works by running the same program simultaneously 25 times and taking the average of the results. This means that if one of the programs is slow, it will affect the overall performance. However, it also includes the minimum time it took to run the program, which is a good indicator of how fast the program can be. This means that if one of the programs is slow, it will affect the overall performance.

Bubble Sort Example

Here’s an example using the Bubble Sort benchmark that I created:

/assets/img/kotlin-performance/2.png

I immediately notice some very high spikes. This must mean that it’s dragging down the average time, right?

/assets/img/kotlin-performance/3.png

Nope.

Kotlin Native performs at the benchmark I would expect it to run, but it’s minimum time is still leagues behind the other languages. This means that even though it can run at a decent speed, it still has a lot of room for improvement. However, let’s remind ourselves that this was measured in microseconds, with a fundamental difference of only just a millisecond or two. This is a very small difference, and it can be attributed to the fact that Kotlin is a newer language and is still being optimized. However, I would expect it to be at least on par with the other languages in the benchmarks.

Why is This?

Let’s take a look at some decompiled Kotlin code. This is a decompiled example of the TabroomAPI library that I created.

/* Decompiler 33ms, total 130ms, lines 156 */
package dev.gmitch215.tabroom.api;

import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Metadata(
   mv = {2, 1, 0},
   k = 1,
   xi = 48,
   d1 = {"\u0000\"\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0004\n\u0002\u0010\u000b\n\u0002\b\u0012\n\u0002\u0010\b\n\u0002\b\u0002\b\u0087\b\u0018\u00002\u00020\u0001B/\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0003\u0012\u0006\u0010\u0005\u001a\u00020\u0003\u0012\u0006\u0010\u0006\u001a\u00020\u0003\u0012\u0006\u0010\u0007\u001a\u00020\b¢\u0006\u0004\b\t\u0010\nJ\t\u0010\u0012\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0013\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0014\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0015\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0016\u001a\u00020\bHÆ\u0003J;\u0010\u0017\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u00032\b\b\u0002\u0010\u0005\u001a\u00020\u00032\b\b\u0002\u0010\u0006\u001a\u00020\u00032\b\b\u0002\u0010\u0007\u001a\u00020\bHÆ\u0001J\u0013\u0010\u0018\u001a\u00020\b2\b\u0010\u0019\u001a\u0004\u0018\u00010\u0001HÖ\u0003J\t\u0010\u001a\u001a\u00020\u001bHÖ\u0001J\t\u0010\u001c\u001a\u00020\u0003HÖ\u0001R\u0011\u0010\u0002\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\u000b\u0010\fR\u0011\u0010\u0004\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\r\u0010\fR\u0011\u0010\u0005\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\u000e\u0010\fR\u0011\u0010\u0006\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\u000f\u0010\fR\u0011\u0010\u0007\u001a\u00020\b¢\u0006\b\n\u0000\u001a\u0004\b\u0010\u0010\u0011¨\u0006\u001d"},
   d2 = {"Ldev/gmitch215/tabroom/api/Judge;", "", "firstName", "", "lastName", "school", "location", "hasParadigm", "", "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", "getFirstName", "()Ljava/lang/String;", "getLastName", "getSchool", "getLocation", "getHasParadigm", "()Z", "component1", "component2", "component3", "component4", "component5", "copy", "equals", "other", "hashCode", "", "toString", "tabroom-api"}
)
public final class Judge {
   @NotNull
   private final String firstName;
   @NotNull
   private final String lastName;
   @NotNull
   private final String school;
   @NotNull
   private final String location;
   private final boolean hasParadigm;

   public Judge(@NotNull String firstName, @NotNull String lastName, @NotNull String school, @NotNull String location, boolean hasParadigm) {
      Intrinsics.checkNotNullParameter(firstName, "firstName");
      Intrinsics.checkNotNullParameter(lastName, "lastName");
      Intrinsics.checkNotNullParameter(school, "school");
      Intrinsics.checkNotNullParameter(location, "location");
      super();
      this.firstName = firstName;
      this.lastName = lastName;
      this.school = school;
      this.location = location;
      this.hasParadigm = hasParadigm;
   }

   @NotNull
   public final String getFirstName() {
      return this.firstName;
   }

   @NotNull
   public final String getLastName() {
      return this.lastName;
   }

   @NotNull
   public final String getSchool() {
      return this.school;
   }

   @NotNull
   public final String getLocation() {
      return this.location;
   }

   public final boolean getHasParadigm() {
      return this.hasParadigm;
   }

   @NotNull
   public final String component1() {
      return this.firstName;
   }

   @NotNull
   public final String component2() {
      return this.lastName;
   }

   @NotNull
   public final String component3() {
      return this.school;
   }

   @NotNull
   public final String component4() {
      return this.location;
   }

   public final boolean component5() {
      return this.hasParadigm;
   }

   @NotNull
   public final Judge copy(@NotNull String firstName, @NotNull String lastName, @NotNull String school, @NotNull String location, boolean hasParadigm) {
      Intrinsics.checkNotNullParameter(firstName, "firstName");
      Intrinsics.checkNotNullParameter(lastName, "lastName");
      Intrinsics.checkNotNullParameter(school, "school");
      Intrinsics.checkNotNullParameter(location, "location");
      return new Judge(firstName, lastName, school, location, hasParadigm);
   }

   // $FF: synthetic method
   public static Judge copy$default(Judge var0, String var1, String var2, String var3, String var4, boolean var5, int var6, Object var7) {
      if ((var6 & 1) != 0) {
         var1 = var0.firstName;
      }

      if ((var6 & 2) != 0) {
         var2 = var0.lastName;
      }

      if ((var6 & 4) != 0) {
         var3 = var0.school;
      }

      if ((var6 & 8) != 0) {
         var4 = var0.location;
      }

      if ((var6 & 16) != 0) {
         var5 = var0.hasParadigm;
      }

      return var0.copy(var1, var2, var3, var4, var5);
   }

   @NotNull
   public String toString() {
      return "Judge(firstName=" + this.firstName + ", lastName=" + this.lastName + ", school=" + this.school + ", location=" + this.location + ", hasParadigm=" + this.hasParadigm + ")";
   }

   public int hashCode() {
      int result = this.firstName.hashCode();
      result = result * 31 + this.lastName.hashCode();
      result = result * 31 + this.school.hashCode();
      result = result * 31 + this.location.hashCode();
      result = result * 31 + Boolean.hashCode(this.hasParadigm);
      return result;
   }

   public boolean equals(@Nullable Object other) {
      if (this == other) {
         return true;
      } else if (!(other instanceof Judge)) {
         return false;
      } else {
         Judge var2 = (Judge)other;
         if (!Intrinsics.areEqual(this.firstName, var2.firstName)) {
            return false;
         } else if (!Intrinsics.areEqual(this.lastName, var2.lastName)) {
            return false;
         } else if (!Intrinsics.areEqual(this.school, var2.school)) {
            return false;
         } else if (!Intrinsics.areEqual(this.location, var2.location)) {
            return false;
         } else {
            return this.hasParadigm == var2.hasParadigm;
         }
      }
   }
}

Already we can see some of the reason for the slow runtime.

These two features are great for making sure that the code is safe and correct, but they come at a cost. The performance of the program is affected by these features, and it can be very slow in some cases.

Conclusion

This was a short analysis about Kotlin’s performance. I think that Kotlin is a great language, and I love using it. However, I think that it has a long way to go before it can be considered a high-performance language. The performance of the program is affected by the features that make it safe and correct, and I think that this is a trade-off that is worth making. However, I would like to see some improvements in the performance of the language in the future.