JavaOne 2026

JavaOne 2026 Session

Duke in front of a whiteboard

How the JVM Optimizes Generic Code - A Deep Dive

Summary

The Java language supports generic classes and methods, since 2004. Using generics, you can write one sort algorithm or one list data structure, and use it everywhere, for many types. This works because a generic data structure or algorithm embodies a pattern of code and/or data that works regularly and reliably for the requested types (These are called "type arguments").

For example, List is a Java interface, and Arrays.sort is a static method. Because List and Arrays.sort are both generic, they can be used safely across many type arguments. A list can contain strings, ints, or frogs. A call to Arrays.sort can sort an array of the same variety of things (assuming frogs can be compared).

Java generics look like C++ templates; in fact, generics and templates share many characteristics. But there is an interesting difference: A Java generic method can be called either with static types (as in C++) or dynamically typed objects (as in JavaScript or Lisp), whereas a C++ template can only expand when given static type arguments.

The difference affects optimization and execution speed. A C++

template stamps out a distinct pile of specialized object code for each template instance. But a Java generic method has two jobs. It should optimize like a template, but it must also offer a single entry point that can operate on dynamic types. It is a little like a C++ template that has one extra "raw instance" that emulates all the other instances.

But how can such a thing optimize, if it must handle both static and dynamic callers? That is the question we tackle in this talk.

Taking the above language features as given, this session deep dives into how the Java Virtual Machine (JVM) processes generics. We will use a small running example, a toy QuickSort algorithm. Running it in various way, we will observe how the JVM can optimizes quick-sorting of arrays of varying types. We will observe a triad of interconnected techniques: type profiling, inlining, and devirtualization. It all works beautifully, just as fast as C++ templates, within certain limits.

We will probe those limits, specifically a problem called profile pollution (or saturation), which blinds the JVM compiler to specialized types, with cascading failures of devirtualization and inlining. When this happens, semantics are preserved (the program produces a correct answer) but there can be a "performance cliff". Parity with C++ templates breaks down, because the program executes as if dynamically typed (only). The answer takes longer to get.

But all is not lost! We will examine a range of tactics, current and future, that can ward off the performance cliff. Either the type profiles must be cleaned up somehow, or there must be an alternative means of supplying the missing type information.

Although much of this technology is three decades old, this talk is timely, because generics are facing new challenges. Project Valhalla will soon deliver a large new language and JVM feature, value classes. A value class instance is no longer a simple polymorphic pointer, so friendly to generic code of the past. A value class is often processed as a small headerless struct.

Inside the JVM, an array of class instances used to be a uniform sequence of dynamically typed pointers, but with Valhalla can look just like a C++ array of structs or C++ objects. This can make some generics harder to optimize, since now the data layout can vary wildly. How does a quick-sort algorithm swap two array elements, when each element might be one pointer, two pointers, a pointer and an int, two ints, or any other combination of field types? Where is C++ template expansion when you need it? There are some partial answers in the short term, which we will demonstrate in today's JVM (as of Java 25).

A long-term answer to this challenge, called "generic specialization", has the JVM do some extra bookkeeping for generic classes and methods, tracking statically-specified type arguments at generic call sites. Using this extra data, the JVM can recompile specialized versions of the code, for a single type argument, just like templates. Of course, the JVM must ensure that this specialization is only called where it is truly applicable. And the specialization should be done only in "hot spots" where the extra compilation work will pay off.

We are not ready to roll out full generic specialization, but we can experiment now with low-level JVM optimizations, that demonstrate the possibility of robust parity with C++ template performance. Today's quick-sort adventure is a step along that path, motivating and informing our next steps. Join us on the journey to Valhalla generics!

Profile

Type: Learning Session (50 min)

Track: Core Java Platform

Audience Level: Beginner

Speaker: John Rose

Session: Thursday, March 19th at 2:00 PM in Auditorium