List initialisation takes long

Hi. I am not sure if this is the right way to draw somebodies attention to this matter. I opened a case in IntelliJ support community back in November 2020 without getting any response.
See: Simple listOf(…) function call takes immensly long, when called the first time – IDEs Support (IntelliJ Platform) | JetBrains.
What can I do?

I’m guessing you are using kotlin jvm (which is the default). Based on that alone I can tell you that your results don’t show anything to worry about.
The problem is not kotlin but how the jvm works. The jvm does a lot of just in time optimizations to your code. This means that you can’t just write simple program like the one you linked and easily time functions.
There are a lot of factors you have to take into account first. I’m not an expert on how to do this manually so I can’t tell you exactly what the issues are, but you generally want to run your code a few times before timing it. You also have to make sure that you actually use the results of the code you test. The jvm will probably detect that your code creates a list and never uses it. This will result in it just not running anything after the first few iterations so your test could result in something like this

// original 
repeat(10) {
    startTime = System.nanoTime()
    l = listOf(1, 1, 1, 1)
    endTime = System.nanoTime()
    println(endTime - startTime)
}
// possible jvm optimization
repeat(2) {
    startTime = System.nanoTime()
    // some additional just in time optimization steps running parallel to this and jvm startup
    l = listOf(1, 1, 1, 1)
    endTime = System.nanoTime()
    println(endTime - startTime)
}
repeat(8) {
    startTime = System.nanoTime()
    // unused list creation can be skipped
    endTime = System.nanoTime()
    println(endTime - startTime)
}

If you want to do a real benchmark you should use JMH. It’s a framework that makes sure that your code is run and timed properly.
It is the standard framework to do any microbenchmark testing on the jvm and you won’t get good results unless you use it (or really know what you are doing in regards to jvm optimizations).

3 Likes

The JVM uses a JIT compiler during runtime, what you are experiencing is known as warm-up time.

2 Likes

I think one reason for the delay is that that’s when it will load, link, and initialise the relevant class(es)/interface(s): it has to locate them on the classpath (e.g. within a JRE-provided jar file), read them (from the filesystem or whatever), verify them, set them up in memory, run any static initialisers, and so on.

In this case, that’s likely to cover some or all of these classes/interfaces:

  • java.io.Serializable
  • java.util.AbstractCollection
  • java.util.AbstractList
  • java.util.Arrays
  • java.util.ArrayList
  • java.util.Collection
  • java.util.List
  • java.util.RandomAccess
  • kotlin.collections.ArraysUtilJVM
  • kotlin.collections.EmptyList
  • kotlin.collections.List

(It looks like those are the ones it will be directly instantiating or using, though I haven’t checked, and the exact time and order of loading classes isn’t always obvious.)

That’s all needed even if no compilation is done.

As you can see, quite a few classes are likely to be loaded at a very early stage of your program, so the loading time for each one probably takes only a small fraction of your measured time.

And all that will only happen once per run (unless you mess with classloaders or similar), and will apply to all programs using those classes, so it’s not really a performance concern. But it’s one of the reasons why timings and benchmarks should always be done on a ‘warmed-up’ JRE, which has already loaded all the necessary classes.

4 Likes

Thanks, guys. That explains a lot. I have enough leads now to handle this from here.

1 Like