There is still a common belief about Java being slow (especially during the startup) and memory-consuming, making it not being the first option for ephemeral service instances, like containers. This blog post pretends to put some light on those assertions, quantifying the impact of a last-generation JVM in a simple, single-threaded, application. We compare the impact of the JVM measuring the execution time and memory spent of a Java QuickSort implementation, comparing it with the execution of a native image generated with the modern GraalVM Ahead-Of-Time (AOT) compiler and the same QuickSort implementation in Go.

Base setup

Tests setup

Each test consists of a program that:

  1. Allocates an N-sized array and populates it with random data.
  2. Sorts the array using a basic QuickSort algorithm.
  3. Checks that the array is correctly sorted.

The tests are repeated for array sizes from 10 to 1_000_000_000 32-bit integers.

The QuickSort program has three implementations:

Test results

Execution time

The image below shows, in logarithmic scale, the execution times (in milliseconds) of the different implementations for the different array sizes:

Remarks:

Resident Set Size (RSS) memory

The maximum RSS has been measured for the executions of the previous section:

Remarks:

Other aspects

Compile time:

Executable size:

Conclusions

This post shows a dummy experiment with a single-thread, memory-intensive application. We put light on some aspects, and the conclusions here may be an aspect to consider in future decisions (Java or not Java? JIT or AOT?) but definitely, you should do your own benchmarks for your workloads: CPU or I/O intensive? Short-lived or long-lived? Few or many instances of your workload?

The above conclusions are open for discussion.

Java JIT vs AOT

GraalVM AOT vs Go

Go is a very mature language and comes with a mature compiler and toolset. It beats GraalVM AOT compiler in terms of compilation time, execution time and executable size.

The GraalVM native-image generator has still room for improvement, but their current results look promising. In future evaluations, we should see how GraalVM executables work with debuggers, profilers, and other tools.