Skip to content

xmlbeans: memory optimization on Xobj (8 bytes per AttrXObj) #992

@patrickmhaller

Description

@patrickmhaller

Dear POI/XMLBeans team,

I need to fill data into an externally provided Excel sheet that unfolds to 600MB JVM heap after parsing into an XSSFWorkbook.
Analysis via JOL shows

  • 2.35 mio org.apache.xmlbeans.impl.store.AttrXobj, worth 216MB
  • 1.17 mio org.apache.xmlbeans.impl.store.ElementXobj, worth 108MB

In attempt to reduce the memory footprint, I propose below non-invasive change that can provide ~3% reduction in memory footprint, depending on the processed Excel file.

By turning int _bits into short _bits, the JVM can better pack Xobjand subclasses.
Xobj and ElementXobj do not change in size due to object alignment gaps.
However AttrXobj shrinks from 96 bytes (with a 7 byte object alignment gap) to 88 bytes (with 1 byte gap).

All 2965 xmlbeans tests succeeded locally, performance looked identical, and none of the assertions triggered.
The proposed patch looks good to me and I'd hope for merging into the next release.

XMLBeans master (unoptimized)

---[ class org.apache.xmlbeans.impl.store.Xobj ]-------------------------------------
org.apache.xmlbeans.impl.store.Xobj object internals:
OFF  SZ                                            TYPE DESCRIPTION               VALUE
  0   8                                                 (object header: mark)     N/A
  8   4                                                 (object header: class)    N/A
 12   4                                             int Xobj._bits                N/A
 16   4                                             int Xobj._offValue            N/A
 20   4                                             int Xobj._offAfter            N/A
 24   4                                             int Xobj._cchValue            N/A
 28   4                                             int Xobj._cchAfter            N/A
 32   4           org.apache.xmlbeans.impl.store.Locale Xobj._locale              N/A
 36   4                       javax.xml.namespace.QName Xobj._name                N/A
 40   4              org.apache.xmlbeans.impl.store.Cur Xobj._embedded            N/A
 44   4         org.apache.xmlbeans.impl.store.Bookmark Xobj._bookmarks           N/A
 48   4             org.apache.xmlbeans.impl.store.Xobj Xobj._parent              N/A
 52   4             org.apache.xmlbeans.impl.store.Xobj Xobj._nextSibling         N/A
 56   4             org.apache.xmlbeans.impl.store.Xobj Xobj._prevSibling         N/A
 60   4             org.apache.xmlbeans.impl.store.Xobj Xobj._firstChild          N/A
 64   4             org.apache.xmlbeans.impl.store.Xobj Xobj._lastChild           N/A
 68   4                                java.lang.Object Xobj._srcValue            N/A
 72   4                                java.lang.Object Xobj._srcAfter            N/A
 76   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesValue      N/A
 80   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesAfter      N/A
 84   4   org.apache.xmlbeans.impl.values.TypeStoreUser Xobj._user                N/A
Instance size: 88 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

---[ class org.apache.xmlbeans.impl.store.AttrXobj ]-------------------------------------
org.apache.xmlbeans.impl.store.AttrXobj object internals:
OFF  SZ                                            TYPE DESCRIPTION                       VALUE
  0   8                                                 (object header: mark)             N/A
  8   4                                                 (object header: class)            N/A
 12   4                                             int Xobj._bits                        N/A
 16   4                                             int Xobj._offValue                    N/A
 20   4                                             int Xobj._offAfter                    N/A
 24   4                                             int Xobj._cchValue                    N/A
 28   4                                             int Xobj._cchAfter                    N/A
 32   4           org.apache.xmlbeans.impl.store.Locale Xobj._locale                      N/A
 36   4                       javax.xml.namespace.QName Xobj._name                        N/A
 40   4              org.apache.xmlbeans.impl.store.Cur Xobj._embedded                    N/A
 44   4         org.apache.xmlbeans.impl.store.Bookmark Xobj._bookmarks                   N/A
 48   4             org.apache.xmlbeans.impl.store.Xobj Xobj._parent                      N/A
 52   4             org.apache.xmlbeans.impl.store.Xobj Xobj._nextSibling                 N/A
 56   4             org.apache.xmlbeans.impl.store.Xobj Xobj._prevSibling                 N/A
 60   4             org.apache.xmlbeans.impl.store.Xobj Xobj._firstChild                  N/A
 64   4             org.apache.xmlbeans.impl.store.Xobj Xobj._lastChild                   N/A
 68   4                                java.lang.Object Xobj._srcValue                    N/A
 72   4                                java.lang.Object Xobj._srcAfter                    N/A
 76   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesValue              N/A
 80   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesAfter              N/A
 84   4   org.apache.xmlbeans.impl.values.TypeStoreUser Xobj._user                        N/A
 88   1                                         boolean NamedNodeXobj._canHavePrefixUri   N/A
 89   7                                                 (object alignment gap)            
Instance size: 96 bytes
Space losses: 0 bytes internal + 7 bytes external = 7 bytes total

---[ class org.apache.xmlbeans.impl.store.ElementXobj ]-------------------------------------
org.apache.xmlbeans.impl.store.ElementXobj object internals:
OFF  SZ                                               TYPE DESCRIPTION                       VALUE
  0   8                                                    (object header: mark)             N/A
  8   4                                                    (object header: class)            N/A
 12   4                                                int Xobj._bits                        N/A
 16   4                                                int Xobj._offValue                    N/A
 20   4                                                int Xobj._offAfter                    N/A
 24   4                                                int Xobj._cchValue                    N/A
 28   4                                                int Xobj._cchAfter                    N/A
 32   4              org.apache.xmlbeans.impl.store.Locale Xobj._locale                      N/A
 36   4                          javax.xml.namespace.QName Xobj._name                        N/A
 40   4                 org.apache.xmlbeans.impl.store.Cur Xobj._embedded                    N/A
 44   4            org.apache.xmlbeans.impl.store.Bookmark Xobj._bookmarks                   N/A
 48   4                org.apache.xmlbeans.impl.store.Xobj Xobj._parent                      N/A
 52   4                org.apache.xmlbeans.impl.store.Xobj Xobj._nextSibling                 N/A
 56   4                org.apache.xmlbeans.impl.store.Xobj Xobj._prevSibling                 N/A
 60   4                org.apache.xmlbeans.impl.store.Xobj Xobj._firstChild                  N/A
 64   4                org.apache.xmlbeans.impl.store.Xobj Xobj._lastChild                   N/A
 68   4                                   java.lang.Object Xobj._srcValue                    N/A
 72   4                                   java.lang.Object Xobj._srcAfter                    N/A
 76   4            org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesValue              N/A
 80   4            org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesAfter              N/A
 84   4      org.apache.xmlbeans.impl.values.TypeStoreUser Xobj._user                        N/A
 88   1                                            boolean NamedNodeXobj._canHavePrefixUri   N/A
 89   3                                                    (alignment/padding gap)           
 92   4   org.apache.xmlbeans.impl.store.ElementAttributes ElementXobj._attributes           N/A
Instance size: 96 bytes
Space losses: 3 bytes internal + 0 bytes external = 3 bytes total

Micro-optimized with "short _bits"

---[ class org.apache.xmlbeans.impl.store.Xobj ]-------------------------------------
org.apache.xmlbeans.impl.store.Xobj object internals:
OFF  SZ                                            TYPE DESCRIPTION               VALUE
  0   8                                                 (object header: mark)     N/A
  8   4                                                 (object header: class)    N/A
 12   4                                             int Xobj._offValue            N/A
 16   4                                             int Xobj._offAfter            N/A
 20   4                                             int Xobj._cchValue            N/A
 24   4                                             int Xobj._cchAfter            N/A
 28   2                                           short Xobj._bits                N/A
 30   2                                                 (alignment/padding gap)   
 32   4           org.apache.xmlbeans.impl.store.Locale Xobj._locale              N/A
 36   4                       javax.xml.namespace.QName Xobj._name                N/A
 40   4              org.apache.xmlbeans.impl.store.Cur Xobj._embedded            N/A
 44   4         org.apache.xmlbeans.impl.store.Bookmark Xobj._bookmarks           N/A
 48   4             org.apache.xmlbeans.impl.store.Xobj Xobj._parent              N/A
 52   4             org.apache.xmlbeans.impl.store.Xobj Xobj._nextSibling         N/A
 56   4             org.apache.xmlbeans.impl.store.Xobj Xobj._prevSibling         N/A
 60   4             org.apache.xmlbeans.impl.store.Xobj Xobj._firstChild          N/A
 64   4             org.apache.xmlbeans.impl.store.Xobj Xobj._lastChild           N/A
 68   4                                java.lang.Object Xobj._srcValue            N/A
 72   4                                java.lang.Object Xobj._srcAfter            N/A
 76   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesValue      N/A
 80   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesAfter      N/A
 84   4   org.apache.xmlbeans.impl.values.TypeStoreUser Xobj._user                N/A
Instance size: 88 bytes
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total

---[ class org.apache.xmlbeans.impl.store.AttrXobj ]-------------------------------------
org.apache.xmlbeans.impl.store.AttrXobj object internals:
OFF  SZ                                            TYPE DESCRIPTION                       VALUE
  0   8                                                 (object header: mark)             N/A
  8   4                                                 (object header: class)            N/A
 12   4                                             int Xobj._offValue                    N/A
 16   4                                             int Xobj._offAfter                    N/A
 20   4                                             int Xobj._cchValue                    N/A
 24   4                                             int Xobj._cchAfter                    N/A
 28   2                                           short Xobj._bits                        N/A
 30   1                                         boolean NamedNodeXobj._canHavePrefixUri   N/A
 31   1                                                 (alignment/padding gap)           
 32   4           org.apache.xmlbeans.impl.store.Locale Xobj._locale                      N/A
 36   4                       javax.xml.namespace.QName Xobj._name                        N/A
 40   4              org.apache.xmlbeans.impl.store.Cur Xobj._embedded                    N/A
 44   4         org.apache.xmlbeans.impl.store.Bookmark Xobj._bookmarks                   N/A
 48   4             org.apache.xmlbeans.impl.store.Xobj Xobj._parent                      N/A
 52   4             org.apache.xmlbeans.impl.store.Xobj Xobj._nextSibling                 N/A
 56   4             org.apache.xmlbeans.impl.store.Xobj Xobj._prevSibling                 N/A
 60   4             org.apache.xmlbeans.impl.store.Xobj Xobj._firstChild                  N/A
 64   4             org.apache.xmlbeans.impl.store.Xobj Xobj._lastChild                   N/A
 68   4                                java.lang.Object Xobj._srcValue                    N/A
 72   4                                java.lang.Object Xobj._srcAfter                    N/A
 76   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesValue              N/A
 80   4         org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesAfter              N/A
 84   4   org.apache.xmlbeans.impl.values.TypeStoreUser Xobj._user                        N/A
Instance size: 88 bytes
Space losses: 1 bytes internal + 0 bytes external = 1 bytes total

---[ class org.apache.xmlbeans.impl.store.ElementXobj ]-------------------------------------
org.apache.xmlbeans.impl.store.ElementXobj object internals:
OFF  SZ                                               TYPE DESCRIPTION                       VALUE
  0   8                                                    (object header: mark)             N/A
  8   4                                                    (object header: class)            N/A
 12   4                                                int Xobj._offValue                    N/A
 16   4                                                int Xobj._offAfter                    N/A
 20   4                                                int Xobj._cchValue                    N/A
 24   4                                                int Xobj._cchAfter                    N/A
 28   2                                              short Xobj._bits                        N/A
 30   1                                            boolean NamedNodeXobj._canHavePrefixUri   N/A
 31   1                                                    (alignment/padding gap)           
 32   4              org.apache.xmlbeans.impl.store.Locale Xobj._locale                      N/A
 36   4                          javax.xml.namespace.QName Xobj._name                        N/A
 40   4                 org.apache.xmlbeans.impl.store.Cur Xobj._embedded                    N/A
 44   4            org.apache.xmlbeans.impl.store.Bookmark Xobj._bookmarks                   N/A
 48   4                org.apache.xmlbeans.impl.store.Xobj Xobj._parent                      N/A
 52   4                org.apache.xmlbeans.impl.store.Xobj Xobj._nextSibling                 N/A
 56   4                org.apache.xmlbeans.impl.store.Xobj Xobj._prevSibling                 N/A
 60   4                org.apache.xmlbeans.impl.store.Xobj Xobj._firstChild                  N/A
 64   4                org.apache.xmlbeans.impl.store.Xobj Xobj._lastChild                   N/A
 68   4                                   java.lang.Object Xobj._srcValue                    N/A
 72   4                                   java.lang.Object Xobj._srcAfter                    N/A
 76   4            org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesValue              N/A
 80   4            org.apache.xmlbeans.impl.store.CharNode Xobj._charNodesAfter              N/A
 84   4      org.apache.xmlbeans.impl.values.TypeStoreUser Xobj._user                        N/A
 88   4   org.apache.xmlbeans.impl.store.ElementAttributes ElementXobj._attributes           N/A
 92   4                                                    (object alignment gap)            
Instance size: 96 bytes
Space losses: 1 bytes internal + 4 bytes external = 5 bytes total

Diff / Patch

diff --git a/src/main/java/org/apache/xmlbeans/impl/store/Xobj.java b/src/main/java/org/apache/xmlbeans/impl/store/Xobj.java
index 55391fe7..ce078228 100644
--- a/src/main/java/org/apache/xmlbeans/impl/store/Xobj.java
+++ b/src/main/java/org/apache/xmlbeans/impl/store/Xobj.java
@@ -41,9 +41,11 @@ abstract class Xobj implements TypeStore {
 
     Xobj(Locale l, int kind, int domType) {
         assert kind == ROOT || kind == ELEM || kind == ATTR || kind == COMMENT || kind == PROCINST;
+        assert (kind & 0xFFFFFFF0) == 0 : "kind exceeds reserved bits in 'short' range:" + kind;
+        assert (domType & 0xFFFFFFF0) == 0 : "domType exceeds reserved bits in 'short' range:" + domType;
 
         _locale = l;
-        _bits = (domType << 4) + kind;
+        _bits = (short)((domType << 4) + kind);
     }
 
     final int kind() {
@@ -1280,18 +1282,26 @@ abstract class Xobj implements TypeStore {
     //
 
     final void setBit(int mask) {
+        assert (mask & 0xFFFF0000) == 0 : "mask exceeds 'short' range:" + mask;
+
         _bits |= mask;
     }
 
     final void clearBit(int mask) {
+        assert (mask & 0xFFFF0000) == 0 : "mask exceeds 'short' range:" + mask;
+
         _bits &= ~mask;
     }
 
     final boolean bitIsSet(int mask) {
+        assert (mask & 0xFFFF0000) == 0 : "mask exceeds 'short' range:" + mask;
+
         return (_bits & mask) != 0;
     }
 
     final boolean bitIsClear(int mask) {
+        assert (mask & 0xFFFF0000) == 0 : "mask exceeds 'short' range:" + mask;
+
         return (_bits & mask) == 0;
     }
 
@@ -2416,7 +2426,14 @@ abstract class Xobj implements TypeStore {
 
     Bookmark _bookmarks;
 
-    int _bits;
+    /* Memory-optimized bit field allows JVM to pack Xobj and subclasses more densely,
+     * e. g. AttrXobj.
+     *  0.. 3: kind
+     *  4.. 7: domType
+     *  8..11: VACANT, STABLE_USER, INHIBIT_DISCONNECT
+     * 12..15: free for internal use
+     */
+    private short _bits;
 
     Xobj _parent;
     Xobj _nextSibling;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions