patrickmhaller opened a new issue, #992: URL: https://github.com/apache/poi/issues/992
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](https://github.com/openjdk/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 `Xobj`and 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; ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
