The Java Garbage Collector: Advantages are Overrated

The garbage collector papers over weaknesses in the design of Java.

ava has an impressive set of garbage collectors with high performance. However, when discussing alternative programming languages, I see all too often that the Java crowd will claim some sort of superiority because of the Java garbage collectors.

There are major flaws with this argument, which I would like to point out here. What is overlooked among the Java fans is that Java needs a high performance garbage collector, due to the design of the language.

Pointer heavy programming was popular in the 90s when Java was designed and garbage collection was a popular research topic. Thus there was a lot of optimism back then that the garbage collector would magically solve all problems. Hence, turning everything into reference objects was a conscious choice in Java that has not aged well.

Real world experience and how our hardware has evolved has proven that this was a big design mistake.

Memory Fragmentation Problem

If you are not following along about what I am talking about, let us look more at the details. Say you define an object in Java like this:

class Point
int x;
int y;
end

In memory this will end up looking something like this:

Layout of Java object in memory
Layout of Java object in memory

In addition to the actual member variables, the useful data, we need a bunch of bookkeeping. Because Java is an object-oriented language, this could be part of a class hierarchy. A variable defined as a Point reference could actually be pointing to a Point3D object. Therefore, to resolve the difference at runtime, we need to store the type of the object.

We also need bookkeeping for the garbage collector such as the mark field. Finally, there might be memory wasted to get everything aligned properly in memory. This may not seem like a big deal for a single object, but it quickly compounds itself. Say you define a rectangle class like this:

class Rect
Point min;
Point max;
end

The min and max define the extent of the rectangle. This means we get the same overhead duplicated many times over, as shown on the left below.

On the left Java style memory fragmentation. On the right contiguous blocks of memory possible in Go, C/C++, Julia etc.
On the left Java style memory fragmentation. On the right contiguous blocks of memory possible in Go, C/C++, Julia etc.

What you really want is something as seen on the right. One continuous block of memory allocated for the rectangle. This requires just one allocation and thus puts less stress on the garbage collector. It represents what you can do in C/C++, Go, Julia or even C# to name some examples. Here is a Go definition that turns into this memory layout:

type Point struct {
x Point
y Point
}

When you create arrays of hundreds of thousands of elements, this problem only grows. For this reason, a Java program produces a huge amount of garbage when it runs. This puts very high demands on the garbage collector. It has to allocate and free memory rapidly as requests come in at a high rate.

In a language that allows you to define memory layout easily, you could allocate 1 million elements in an array in one operation and free it in another. In Java, you risk 1 million allocations and later 1 million collections. This means when you have lots of small allocations, Java will come on top in benchmarks. As an example, we can look at this micro-benchmark comparing Go and Java:

Java wins by a good margin, thanks to its fast garbage collector. If you compare with the other benchmarks, Go will more frequently come out on top.

But here is the problem with this benchmark. In a language like Go with proper pointer and the ability to control memory layout, you can simply create a secondary allocator to handle this case. How does this work? You simply allocate one big chunk of memory and then piece out individual objects to the binary tree as needed.

var node = arena.New(value, left, right)
arena.Free(node)

Above shows a simple example from Go, how you would call this. It is an example of creating a node with some value having a left and a right branch. Later we free the node using the allocator. Yes, this of course involves manual memory management, but it is the kind of choice you can make when you need to optimize a performance critical part of the code. In most cases you don’t need to do this.

Compare this with the Java engineer. They might instead have to tune the garbage collector or switch to another one, because the ability to tune how the program uses the memory is far more limited in Java.

Implications and Conclusions

Does this mean garbage collectors are bad? No, garbage collectors are a good thing but just because you have one doesn’t mean you should generate as much garbage as possible. This is where Java went wrong. They thought GC technology would advance in the future to make the problem go away, but here we are and the problem didn’t really go away.

This isn’t to suggest Java is a bad language. Java has mitigated its weaknesses by simply investing a ton of money in a superior garbage collector.

But this means that competing languages such as Go, Nim, Julia, etc., can get away with a far simpler garbage collector than Java and still get the same or better performance. In other words, having a Lamborghini garbage collector isn’t the awesome advantage that a lot of Java developers think it is. It is simply a necessity because Java produces huge amounts of garbage.

And if you don’t believe me, then ask yourself why Java is getting value types? The new ValueType in Java.

The answer is simple. The Java developers realized they made a mistake and are playing catchup. What is silly about this is that they spent all these billions to get a garbage collector to avoid the need for a value type and then they realized they had to get it anyway.

Geek dad, living in Oslo, Norway with passion for UX, Julia programming, science, teaching, reading and writing.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store