Final RFR: 8005232 (JEP-149) Class Instance size reduction

David Holmes david.holmes at oracle.com
Sun Jan 6 22:46:51 UTC 2013


This is the official RFR for this work. Thanks to everyone for previous 
comments and feedback.

Webrev:

http://cr.openjdk.java.net/~dholmes/8005232/webrev/

Description below.

Thanks,
David
------

JEP-149 looks at dynamic memory footprint reductions in Java 8.

http://openjdk.java.net/jeps/149

This CR covers the "Class Instance Size Reduction" project of that JEP.

In Java 8, using a 32-bit example, a java.lang.Class instance is 112 
bytes consisting of:

- 8 byte object header
- 20 declared fields (mostly references, some int)
- 5 injected fields (3 references, 2 ints)

That gives: 8 + (20*4) +(5*4) = 108 bytes. But as we need 8-byte 
alignment that increases to 112 bytes.

Nine of the reference fields are to SoftReferences (null if not used) 
that hold cached reflection data (declared methods, fields, constructors 
etc), all of which must be cleared upon class redefinition. If 
reflection is not used then these fields are wasting space. There are a 
number of fields related to annotations, and again if unused these are 
wasting space - however as JSR-308 is doing a lot of work on annotation 
types it was decided to leave the annotation related fields alone. There 
are two further fields (cachedConstructor and newInstanceCallerCache) 
that pertain to use of the newInstance() method. The very existence of 
these fields suggests that newInstance is a more common reflection 
construct to support. Further these are direct references not 
soft-references and they are not cleared upon class redefinition 
(arguably a bug), and so for those reasons we also exclude those fields 
from the present changes.

The original proposal simply moved all the reflection caching 
soft-references into a separate helper object. That proposal was sent 
for review here:

http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-April/009749.html

and it was noted by Brian Goetz that additional savings could be made if 
we held one soft-reference to the helper object rather than a direct 
reference to a helper containing soft-references.

Peter Levart stumbled into this when he was devising solutions to an 
annotations processing synchronization bottleneck reported by Alexander 
Knoller:

http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-November/012049.html

After narrowing the scope to the reflection objects the discussion 
continued here:

http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-December/012911.html

With Peter's final proposed patch here:

http://dl.dropbox.com/u/101777488/jdk8-tl/JEP-149.c/webrev.04/index.html

In this design we only keep a soft-reference to a ReflectionData object 
which in turn holds the original fields (but directly) for the cached 
reflection objects. The ReflectionData object is cleared upon class 
redefinition and each ReflectionData instance tracks the class 
redefinition count at the time it was created. This in turn required a 
seperate redefinition count to be maintained for the annotations 
processing. As a result we have the following layout changes:

- 8 reference fields moved (the reflection caches)
- 1 int moved (the class redefinition count)
- 1 reference added (for the SoftReference to the ReflectionData)
- 1 int added (the class redefinition count for annotations)

This is a saving of 7 reference fields ie. 28 bytes, resulting in a new 
Class instance size of 80 bytes. This saves a further 4 bytes due to the 
fields being 8-byte aligned without any need for padding. So overall we 
save 32 bytes per class instance.

The ReflectionData instance itself consumes 48 bytes, while a 
SoftReference consumes 32 bytes.

For classes that don't use reflection this is an obvious win of 32 bytes 
per class. For classes that use all 8 reflection caches this is also a 
win as we save 7 SoftReferences ie 224 bytes.

For classes that only use one cached reflection object, however, there 
is a space penalty. The existing layout would consume 112 bytes for the 
Class instance, plus 32 bytes for the SoftReference to hold the cached 
array. A total of 144 bytes. The new layout consumes 80 bytes for the 
Class instance, 32 bytes for the SoftReference to the ReflectionData, 
and 48 bytes for the ReflectionData instance: a total of 160 bytes. 
Hence we have a 16 byte space penalty if only one reflection cache is 
needed. Note that if two reflection caches are used then we are again in 
front as the new scheme requires no further allocations, where the old 
would add a second SoftReference at 32-bytes, thus giving the new scheme 
a 16 byte advantage.



More information about the core-libs-dev mailing list