Java’s Enum.values() Hidden Allocations

I recently profiled an app of mine. During profiling, I’ve noticed tons of array allocations. Something like:

Well easy, a quick grep for TypeInfo[] array. Nothing. Ah, quick grep for TypeInfo collections. Nothing! Huh? Where the hell do I allocate the array then?
Ok, more profiling! So, I enabled flight recorder with ‘-XX:+UnlockCommercialFeatures -XX:+FlightRecorder’. Then did a recording with Java Mission Control, capturing the allocation stack traces:

Ok, the TypeInfo.values() method allocates the memory. TypeInfo is a enum, and I’m using the built in values() method. The code looked something like this:

Do you see the allocation? Why should it allocate that many arrays? The Enum values are constant, so it should be able to initialize an array once?
Ok, let’s take a closer look and decompile the class file:

javap -c TypeInfo.class | grep -A 10 values

And we get:

  public static info.gamlor.blog.TypeInfo[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[Linfo/gamlor/blog/TypeInfo;
       3: invokevirtual #2                  // Method "[Linfo/gamlor/blog/TypeInfo;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[Linfo/gamlor/blog/TypeInfo;"
       9: areturn

As we can see, it deferences a static array of the Enum values. Then it clones that array before returning it, causing an array allocation. Why does it do that? It is a defensive copy:
Java’s arrays are a mutable. If values() just returns the reference to the original array, then some code might change the array’s content. That creates havoc, since it would change what Enum.values() returns. Therefore, the defensive copy.

Safety First, Copy It

So, after seeing this, it is easy to fix our code. We call Enum.values() once, cache the array and use it for the parsing:

Et voila, the allocations are gone =)

Tagged on: , ,

Leave a Reply

Your email address will not be published. Required fields are marked *