-
Notifications
You must be signed in to change notification settings - Fork 813
Description
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;