Peter is a DZone MVB and is not an employee of DZone and has posted 142 posts at DZone. You can read more from them at their website. View Full User Profile

Surprising results of autoboxing

01.28.2012
| 5857 views |
  • submit to reddit

There are a number of surprising consequences of auto-boxing. Some are more widely known than others. Most of them are due to the effect of caching of some auto boxed objects.

 

== and equals may or may not match

If you run the program AutoboxEqualsMain with default options.
All Boolean are cached.
All Byte are cached.
The first auto-boxed char is 0 and the last is 127
The first auto-boxed short is -128 and the last is 127
The first auto-boxed int is -128 and the last is 127
The first auto-boxed long is -128 and the last is 127
No Float are cached.
No Double are cached.

For those that know that == compares references, for Integer or any Object type.

Run the program again with -XX:+AggressiveOpts on Java 7 and you get almost the same result.
All Boolean are cached.
All Byte are cached.
The first auto-boxed char is 0 and the last is 127
The first auto-boxed short is -128 and the last is 127
The first auto-boxed int is -128 and the last is 20000
The first auto-boxed long is -128 and the last is 127
No Float are cached.
No Double are cached.
Note: This option has increased the maximum for the Integer cache.

 

The performance improvements

The memory size for an int[] and an ArrayList<Integer> can be almost the same size for cached values. If you run this program which builds a collection of both using the numbers 1 to 16,000 with -XX:-UseTLAB and -XX:+AgressiveOpts you can get this result.
The int[16000] took 64592 bytes and new ArrayList() with 16000 values took 65048 bytes
This result is surprising for two reasons. Firstly, it is run in a 64-bit JVM. The ArrayList is an array of references, however the JVM can use 32-bit reference for up to 32 GB of heap memory. Note: You can use direct memory and memory mapped files to use much more than 32 GB, but as long as your heap is smaller than 32 GB it can use 32-bit references.
Secondly, the objects themselves don't appear to take any space. This is because all the values are cached before the program starts so you don't see the space they occupy.

Note: being such a short test the values for size you get vary with each run. I ran this test a few times and took the lowest result. The highest results were not that much higher (within 20%)

 

Auto-boxed objects don't get garbage collected

If you use auto-boxed objects as keys, they might never be unloaded.
Map<Long, String> keyValueMap = new WeakHashMap<Long, String>(10000);
for (long i = 1; i <= 8192; i *= 2)
    keyValueMap.put(i, "key-" + i);
System.out.println("Before GC: " + keyValueMap);
System.gc();
System.out.println("After GC: " + keyValueMap);
The keys of the map are not being held so you would expect them to be cleaned up on a GC. What might be surprising is that not all keys are cleaned up.
Before GC: {8192=key-8192, 4096=key-4096, 2048=key-2048, 1024=key-1024, 512=key-512, 256=key-256, 
    128=key-128, 64=key-64, 32=key-32, 16=key-16, 8=key-8, 4=key-4, 2=key-2, 1=key-1}
After GC: {64=key-64, 32=key-32, 16=key-16, 8=key-8, 4=key-4, 2=key-2, 1=key-1}
Note: I increased the initial capacity of the WeakHashMap so that the keys would appear in a predictable order.

 

Don't use auto-boxed object for as locks

This goes up there with not using string literals for locks
synchronized("lock one") { // DON'T do this.
But what can make using auto-boxed values worse is that your program can work fine when tested, provided the objects locked are small. When you program happens to use a larger value, the locking suddenly fails.
Object o = 
Integer lock = o.hashCode() & 255;
synchronized(lock)  { // DON'T do this either.
This could look like a clever way to have locks for all objects which are equal. However, its very brittle and obtuse and you could find your program fails unexpectedly in ways which are difficult to reproduce e.g. depending on whether you have use -XX:+AggressiveOpts If you have more than one library or section of code which does this, you could get bizarre deadlocks between unrelated code.

 

The code

 

From http://vanillajava.blogspot.com/2012/01/surprising-results-of-autoboxing.html

Published at DZone with permission of Peter Lawrey, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: