Дата публикации: 04.11.2013 8:47:11
Caching of an empty array is a well-known pattern to improve performance. However, it is difficult to use it in generified classes.
Out of curiosity, I created a custom implementation of the array creation method based on Array.newInstance. To cache empty arrays, I use synchronized WeakHashMap, which maps any given component type to a weak reference to the corresponding empty array. This is not the fastest way, but it does not lead to memory leaks.
private static final Map<Class<?>, Reference<?>> map = new WeakHashMap<Class<?>, Reference<?>>(); @SuppressWarnings("unchecked") public static <T> T[] newInstance(Class<T> type, int length, boolean cache) { if (!cache || length != 0) { return (T[]) Array.newInstance(type, length); } synchronized (map) { Reference<?> ref = map.get(type); Object array = (ref == null) ? null : ref.get(); if (array == null) { array = Array.newInstance(type, length); map.put(type, new WeakReference(array)); } return (T[]) array; } }
Note that the method returns an array of a given type. I used the SuppressWarnings annotation to suppress warnings about unchecked casts.
Consider the results of the test application. The left column shows the number of iterations. During each iteration, an empty array is created for every given component type. The middle column shows the average time of an empty array creation. The right column shows the average time of creating and retrieving the shared empty array. Frankly, I was surprised that the caching of a single array is slower than caching of several ones.
1 class per attempt
88 different classes per attempt
Cached empty arrays can be useful for the JVM too. For example, when calling varargs methods without arguments a new empty array is created every time. I do not think that anyone expects such behavior.
What do you think?
PS. This article was originally posted on the Java.net site.