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

Peter Levart peter.levart at
Wed Jan 9 13:04:20 UTC 2013

On 01/09/2013 01:19 PM, Aleksey Shipilev wrote:
> Good stuff.
> On 01/07/2013 02:46 AM, David Holmes wrote:
> Sorry for obnoxious first-time reviewer questions:
>   a) I think the CAS loop in newReflectionData() is misleading in its
> reuse of the parameters. Can we instead inline it? Or, can we read the
> fields for $reflectionData and $classRedefinedCount, with no parameters
> passed?
It was originally written as one method. Performance tests showed that 
some (i think two more) of the public API methods were more aggressively 
in-lined when split in two methods. I think it would not hurt 
performance practically if the original variant was used.
>   b) Had we considered filling up the complete ReflectionData eagerly on
> first access? This will make ReflectionData completely final. I would
> guess this goes against the per-use laziness?
Certainly there are usages where only one part is ever needed. For 
example only getDeclaredXXX but not getXXX which also triggers loading 
in superclasses and then aggregating...
>   c) What's the merit of using Unsafe instead of field updaters here?
> (Avoiding the dependency on j.u.c?)
Mainly because of initialization-loops. AtomicReferenceFieldUpdater uses 
Class.getDeclaredField(name), which in turn needs ReflectionData, ...
Strictly speaking, CAS is actually not needed here. Since we keep 
classRedefinedCount snapshot inside the ReflectionData, any races that 
would install "older" ReflectionData over "newer", would be quickly 
caught at next invocation to reflectionData(). So if there are any 
objections to usage of Unsafe, it can be removed and replaced by simple 
volatile write.
>   d) I think the code can be further simplified if we stick with
> reflectionData() returning non-null object all the time, and check for
> useCaches instead in the usages, at the expense of creating the methods
> which actually get the reflection data.
I don't quite understand what you mean. Are you suggesting to double all 
the methods with variants that don't use reflectionData? If you check 
the usages you can see that the "caching aspect" is tested at two places 
in each method, the rest of code is the same for caching/non-caching 
>   e) Should useCaches be final? That will allow aggressive optimizations
> for (c).
Again the initialization order issues (see checkInitted()). The value 
for useCaches comes from system properties. Might be final and be later 
overwritten via Unsafe, but wouldn't this defeat optimizations? (or if 
not, wouldn't then those optimizations take the wrong code-path?)

Regards, Peter

>> 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.
> Shameless promotion follows. This tool [1] should help to estimate the
> class layout in the face of object alignment, compressed references,
> paddings, alignment and whatnot.
> -Aleksey.
> [1]

More information about the core-libs-dev mailing list