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

Peter Levart peter.levart at gmail.com
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: http://cr.openjdk.java.net/~dholmes/8005232/webrev/ 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 reflectionDataandreflectionData and reflectionDataandclassRedefinedCount, 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 variants. 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] https://github.com/shipilev/java-object-layout/



More information about the core-libs-dev mailing list