Is autoboxing wrecking your Java application's performance? 🤔

While working on the instructional regarding how to convert an array to an ArrayList in Java I noticed that the performance of the call to the Google Guava newArrayList method appeared to be quite slow — this was a mistake, and the reason has to do with Java autoboxing performance — we’ll go over this here along with Java unboxing performance.

Java Autoboxing and Unboxing Performance TOC

Note that Java autoboxing is the same as automatic boxing and I use these words interchangeably in this document.

Summary of Findings

Below I’ve included the combined chart so you can compare the performance results for boxing and unboxing operations in Java.

While unboxing has a bit of a performance hit associated with it, it’s on par with the performance of the example where unboxing is not required.

What should be abundantly clear from this chart is that autoboxing in Java is an expensive operation.

This makes sense since when an autoboxing operation takes place Java primitives are wrapped in the object wrapper equivalent which requires both time as well as memory.

We’re going to focus on the performance when autoboxing in Java in this document and save the memory requirements for another article.

The remainder of this article includes how this issue was discovered along with the evidence that supports this finding.

An errant performance test which included Java autoboxing

As mentioned in the introduction, the Google Guava newArrayList method is, in fact, not slow — rather I was testing using an array of primitive integers and that caused the Java compiler to autobox these values into their wrapper object equivalent — it was the process of autoboxing that was interfering with the performance test.

Autoboxing, in particular, is an expensive operation in Java and can have a considerable impact on an application’s performance.

We can see the source code for the Google Guava Lists newArrayList method on the right side of this page — note that there’s nothing particularly interesting about how this method converts an array into an ArrayList in Java.

The performance penalty when the primitive integer was autoboxed into an instance of java.lang.Integer may have been missed if the size of the array was small enough or if I was only doing this to one variable.

In this case, I set up an example using an array of size 10,000, which is large enough to expose the issue.

In the next section we’ll take a look at the Java autoboxing performance along with the tests that were developed to show the cost of performing this operation.

Java Boxing Performance

Below I’ve included a chart that demonstrates the performance between the two Java applications — one where boxing is used and the other where boxing is not present.

Note that the Java example that requires boxing takes so much time to execute that we almost don’t see the performance of the example where boxing is not needed.

In the next two sections we’ll take a look at the evidence backing these numbers.

Java Performance: With Autoboxing

The performance test that I developed to examine how the Google Guava Lists newArrayList method can be seen below.

Note that line #28 is taking an array of primitive integer values and this is where the autoboxing is taking place.

The performance monitor starts on line #24 so the autoboxing happens during the performance test and this produces numbers which are not accurate.

An example, written in Groovy script, with pointers to line 16 and 19 which entails use the a primitive integer and primitive integer array that will be autoboxed into an array of java.lang.Integer objects on line #28. Note that the performance has been noted at the bottom of the image and is rather excessive at 282662.2 ms after running this script five times.
An example of Java 8 performance which requires autoboxing and takes 282662.2 ms in total to run this Groovy script five times.

In this example we can see that the average time spent converting the array to an ArrayList in Java five times appears to be rather excessive at 282662.2 milliseconds (that’s 282.66 seconds or 4.711 minutes)!

On the right I’ve included a similar Java 8 autoboxing performance example to the Groovy script above however I’ve changed the performance test such that it can run in the TIO interpreter, which has a timeout of 60 seconds and does not allow for 3rd party dependencies to be included when example code is executed.

Autoboxing in Java Example

Below I’ve included the full working Java 8 autoboxing performance test which uses Java components and is written using the Groovy programming language.

Note that line #16 creates an array of primitive integers and line #19 adds random primitive integer values to that array.

You should be able to run this script as-is by pasting it into the groovyConsole.

On the right is a link to the GitHub gist for the Java autoboxing performance test source code (this is, in fact, written using the Groovy scripting language however I make an effort to explicitly utilize Java components).

Java Performance: Without Autoboxing

Below I’ve included the example Groovy script which contains adjustments such that the autoboxing performance penalty is not present in this test.

You should be able to paste this script into the Groovy Console and run it without any changes required.

Pay particular attention to lines #16 and #19, where we create an array of type java.lang.Integer, which is populated by instances of java.lang.Integer — there are no primitives used here!

An example, written in Groovy script, with pointers to line 16 and 19 which uses instances of java.lang.Integer instead of a primitive int. Note that no autoboxing will be required when the Google Guava Lists asList method is called on line #28. The performance has been noted at the bottom of the image at 2067.2 milliseconds after running this script five times.
An example of Java performance which DOES NOT require autoboxing and takes 2067.2 ms in total to run this Groovy script five times.

In this example we can see that the average time spent converting the array to an ArrayList in Java five times appears to be rather impressive when compared with the previous example at 2067.2 milliseconds (that’s 2.0672 seconds or 0.0344533 minutes)!

This difference is substantial and clearly demonstrates the performance problem that can come from autoboxing in Java.

Modifying just two lines of code to eliminate autoboxing in Java resulted in a 99.27% improvement in performance.

Below I’ve included the full working Java 8 performance test which uses Java components and which is written using the Groovy programming language.

Note that line #16 creates an array of type java.lang.Integer and line #19 adds random java.lang.Integer values to that array — there is no need for autoboxing on line #28.

You should be able to run this script as-is by pasting it into the groovyConsole.

On the right I’ve included a similar Java 8 performance example which relies on values of type java.lang.Integer juxtaposed with primitive integers and hence does not require any autoboxing.

In this Groovy script I’ve changed the performance test such that it can run in the TIO interpreter, which has a timeout of 60 seconds and does not allow for 3rd party dependencies to be included when example code is executed.

Performance test without autoboxing in Java Example
An example, written in Groovy script, with pointers to line 16 and 19 which uses instances of java.lang.Integer instead of a primitive int. Note that no autoboxing will be required when the Google Guava Lists asList method is called on line #28. The performance has been noted at the bottom of the image at 2067.2 milliseconds after running this script five times.
An example of Java performance which DOES NOT require autoboxing and takes 2067.2 ms in total to run this Groovy script five times.

We’ll take a look at unboxing performance in Java in the next section.

Java Unboxing Performance

The performance between converting a list of java.lang.Integer objects to an array of the same and converting a list of java.lang.Integer objects into an array of primitive integers, which requires unboxing is very close to the same in terms of milliseconds.

We can compare the performance of the two operations in the following chart.

The lesson we can draw out of this section on unboxing is clear: when it comes to performance, we need to be careful when utilizing autoboxing, in particular, as that can have a significant impact on the performance of the application.

Java performance example where unboxing is required

In the image below the block of code between lines 36 and 40 is where we should focus out attention.

Line #38 is where the unboxing happens.

The outerCtr loop is here for the purposes of exacerbating any performance differences since these two operations (with and without unboxing) are very fast.

In this example script unboxing is required when converting from an Integer to a primitive int on line 38.

This script was executed five times and has an average execution time of 43549.0 ms (43.5 seconds).

Unboxing, in this case, does not appear to be an expensive operation as the primitive value already exists inside the Integer object and can be read quickly.

This Java unboxing performance example was executed five times and shows an average execution time of 43549.0 ms (43.5 seconds) for the block of code that includes the unboxing operation (see lines 34-42, and line #38 specifically).
Java Unboxing Performance Example

Java performance example where unboxing is not required

In the following example script unboxing is not required when converting from an Integer to a an Integer on line 38.

This script was executed five times and has an average execution time of 45016.8 ms (45.0 seconds).

Unboxing, in this case, is not required since we’re moving a reference to an Integer from an ArrayList to an Array.

I’m not sure why this operation appears to be slightly slower than the one which requires unboxing — in fact I’d expect the previous example to take slightly longer than this one.

This Java performance example where unboxing is not required was executed five times and shows an average execution time of 45016.8 ms (45.0 seconds) for the block of code between lines 34-42 -- see line #38, specifically.

This concludes the section on unboxing performance in the Java Programming Language — the article conclusion follows.

Article Conclusion

In conclusion, while autoboxing in Java offers a convenient bridge between primitive types and their corresponding wrapper classes, it’s clear that this convenience comes with a potentially significant performance penalty.

The benchmarks and examples discussed in this article underscore the importance of being mindful of boxing and unboxing operations, especially as it pertains to applications where performance is especially important.

By making simple modifications to our code, such as avoiding unnecessary autoboxing, in particular, we can achieve significant improvements in execution speed and efficiency.

Software engineers need to understand the underlying mechanisms of the Java language features we use, ensuring that our applications are not only functional but also optimized for speed.

The case study presented here demonstrates that with careful consideration and minor adjustments, we can overcome the pitfalls of autoboxing and significantly enhance our Java applications’ performance.

Finally, note that Project Valhalla should improve the performance of the Java Programming Language and the introduction of value types should help with autoboxing performance, in particular (see also Project Valhalla on Wikipedia and on GitHub).

If you’re looking to hire a Temporary CTO then I might be able to help you — schedule an appointment with me today and we’ll discuss your requirements in more detail.

See Also

  1. Tutorial: Learn how to add elements to a List in Java!
  2. Oracle Tutorial: Autoboxing and Unboxing
  3. See the performance engineering category

Frequently Asked Questions (FAQ)

This section includes frequently asked questions about autoboxing and auto unboxing as it pertains to the Java Programming Language.
What is autoboxing in Java?

Autoboxing (automatic boxing) in the Java Programming Language is a feature whereby the Java compiler automatically converts between the primitive types and their corresponding object wrapper classes — for example, converting an int to an java.lang.Integer, a double to a java.lang.Double, etc., without requiring explicit code to do so.

This feature simplifies the coding process by allowing programmers to mix primitive and wrapper types, relying on the compiler to add conversion code where necessary.

What is unboxing in Java?

Unboxing in the Java programming language is a feature whereby the Java compiler automatically converts between primitive object wrapper classes and their corresponding primitive type — for example converting from an instance of java.lang.Integer to an int, an instance of java.lang.Double to a double, etc, without requiring that code be written to perform this operation.

When was autoboxing introduced in Java?

The Autoboxing feature was introduced into the Java Programming Language with the release of Java 1.5 (AKA Java 5 / Java SE 5.0) in September 2004.

author avatar
ThosPFuller
I am a software engineer based in Northern Virginia (USA) and this website focuses on content engineering, content experiments, web development, search engine optimization and digital marketing ideas.

ThosPFuller

I am a software engineer based in Northern Virginia (USA) and this website focuses on content engineering, content experiments, web development, search engine optimization and digital marketing ideas.

Leave a Reply