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