JDK-8024912 : Subclass instance fields are laid out with alignment gaps
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2013-09-17
  • Updated: 2020-02-11
  • Resolved: 2020-01-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdResolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
Field layout code starts laying out the instance fields block at super-klass instance boundary. This quirk makes the classes like this:

    public static class A {
        private boolean b;
    }

    public static class B extends A {
        private boolean b;
    }

    public static class C extends B {
        private boolean b;
    }

...to be laid out like this:

 C object internals:
   OFFSET  SIZE    TYPE DESCRIPTION                    VALUE
        0    12         (object header)
       12     1 boolean A.b                            N/A
       13     3         (alignment/padding gap)
       16     1 boolean B.b                            N/A
       17     3         (alignment/padding gap)
       20     1 boolean C.b                            N/A
       21     3         (loss due to the next object alignment)
  Space losses: 6 bytes internal + 3 bytes external = 9 bytes total

It seems legal to lay out the fields like this instead:

  C object internals:
   OFFSET  SIZE    TYPE DESCRIPTION                    VALUE
        0    12         (object header)
       12     1 boolean A.b                            N/A
       13     1 boolean B.b                            N/A
       14     1 boolean C.b                            N/A
       15     1         (loss due to the next object alignment)
  Space losses: 0 bytes internal + 1 bytes external = 1 bytes total

Which saves us 8 bytes per instance. This is layout change is OK, since we don't need booleans to be aligned by 4 (in fact, if we put all three booleans in the same class, they will be laid out exactly like this, side-to-side). The only reason we've got alignment is because the superclass instance size was the multiple of 4.
Comments
Reopening since the mentioned "Jiangli's analysis for JDK-7007564" is not nearly as complete as the analysis performed here. Since the analysis in JDK-7007564 is very basic, and also because the results of the analysis in this issue marks better benefits, it seems incorrect to WNF this issue.
10-02-2014

Closing as WNF based on Jiangli's analysis for JDK-7007564.
10-02-2014

Updated data on the set of heapdumps we have internally, now with the arrays included. These heaps dumps still raise the question about representativity. There were also a few quirks in the processing scripts which yield the underestimated metrics. This is why the data is slightly different even though arrays are not affected by this RFE. For this change, we have 0.025% average and 0.12% max improvement in heap occupancy. The summary quantiles are: 0.000% Min 0.007% 1st Qu. 0.019% Median 0.025% Mean 0.038% 3rd Qu. 0.118% Max.
18-10-2013

This issue can be also solved with JDK-8024913.
18-10-2013

I have also munched through the set of heap dumps we have internally. These heaps dumps raise the question about representativity, but still. Note that the data below is the *underestimate*, because these are counting only the classes, not the arrays. Large arrays dominate the heap, taking the class improvements down. For this change, we have 0.02% average and 0.05% max improvement in heap occupancy on average. The summary quantiles are: 0.000% Min 0.006% 1st Qu. 0.014% Median 0.018% Mean 0.029% 3rd Qu. 0.053% Max.
10-10-2013

"Java Field Layouts: Qualitative Study on Maven Central" http://cr.openjdk.java.net/~shade/papers/2013-shipilev-fieldlayout-latest.pdf This report estimates up to 1.8% of real-world classes are benefiting from this improvement, with average 10% reduction in memory footprint per class.
03-10-2013

There was a similar proposal suggested by Vladimir Kozlov. Experiments using the rt.jar seemed to indicate the gaps between the first non-static field in child class and the last non-static field in superclass are not common cases. Please see JDK-7007564 for details.
17-09-2013

Our booleans are already 1-byte long, at least on x86. Hence this is not about packing the booleans, but rather eliminating the gaps between them. As I said in the description there, if you do just three booleans in the *same* class, i.e.: public static class A { private boolean b1, b2, b3; } ...you will yield the layout we are after here. Hence this seems to be the general question to the layout code, not the particular optimization proposed here. Let's answer them though. AFAIU, all our current target platforms are capable of doing byte-wide loads and stores. If we indeed have the word-tearing for reading/writing 1-byte data locations, that means we have to pad all the booleans and bytes or beef them up to take several bytes, everywhere, including the case above. I don't think we provision this yet? I think some ARMs have the penalty accessing subwords? Of course we risk greater false sharing because the objects are denser; but the modus operandi seems to optimize the memory footprint, and then deal with false sharing in selected cases (e.g. with @Contended). Again, these questions really pertain to the current layout code, not the optimization proposed.
17-09-2013

If you pack boolean fields into bytes is there a risk of word-tearing? Can all platforms issue byte-wide loads and stores? What is the performance impact of using unaligned subword accesses? Do we risk increased false sharing?
17-09-2013