I read this week about SAP publishing a free Memory Analyzer. I first
tried it on a OutOfMemory heap dump of an commercial formatter which we
use in that project that consumed so much of my time lately. It was an
immediate eye opener.
So I wanted to play with this really great tool a little more and ran a
big document which I knew would cause an OutOfMemoryError at 64MB heap
size. Here's what came out:
Class Name |Objects
|Shallow Heap |Retained Heap |Perm
---------------------------------------------------------------------------------------------------------------------
org.apache.fop.fo.properties.CondLengthProperty |
315'760| 7'578'240| 7'578'240|
java.util.WeakHashMap$Entry |
121'873| 4'874'920| 8'861'568|
org.apache.fop.fo.flow.Block |
26'391| 4'855'944| 54'554'584|
org.apache.fop.fo.properties.SpaceProperty |
87'592| 4'204'416| 7'160'880|
org.apache.fop.fo.properties.CommonBorderPaddingBackground |
78'940| 3'789'120| 16'419'968|
org.apache.fop.fo.properties.KeepProperty |
110'661| 3'541'152| 3'541'152|
org.apache.fop.fo.FOText |
30'461| 2'924'256| 52'488'224|
org.apache.fop.fo.properties.CommonFont |
56'859| 2'729'232| 3'638'976|
org.xml.sax.helpers.LocatorImpl |
109'431| 2'626'344| 2'626'344|
org.apache.fop.fo.flow.TableCell |
23'154| 2'593'248| 54'296'024|
org.apache.fop.fo.properties.CondLengthProperty[] |
78'940| 2'526'080| 10'102'592|
org.apache.fop.fo.properties.CommonBorderPaddingBackground$BorderInfo[]|
78'940| 2'526'080| 2'526'080|
org.apache.fop.fo.properties.NumberProperty |
98'304| 2'359'296| 3'932'184|
org.apache.fop.fo.properties.CommonHyphenation |
56'852| 2'274'080| 2'274'080|
char[] |
63'420| 1'931'488| 1'931'488|
org.apache.fop.fo.properties.LengthRangeProperty |
37'843| 1'513'720| 1'513'736|
org.apache.fop.fo.flow.TableColumn |
14'687| 1'409'952| 4'829'912|
org.apache.fop.fo.properties.CommonMarginBlock |
30'592| 1'223'680| 4'160'448|
org.apache.fop.fo.FONode[] |
44'346| 1'064'304| 55'383'904|
org.apache.fop.fo.properties.PercentLength |
26'402| 1'056'080| 1'689'728|
java.lang.Double |
57'931| 926'896| 926'968|
java.lang.String[] |
57'188| 920'096| 943'640|
org.apache.fop.fo.properties.CommonRelativePosition |
26'391| 844'512| 844'512|
java.lang.String |
33'367| 800'808| 1'794'048|
java.lang.Integer |
45'526| 728'416| 729'032|
2'221 more... |
| | |
Total of 2'246 entries
|1'818'755| 67'134'104| |
---------------------------------------------------------------------------------------------------------------------
Immediately shows that Andreas' recent change (rev 554091) for switching
off the SAX Locators can save a lot of memory.
I remembered Andreas working on a property cache a couple of weeks ago.
Seems to work fine on EnumProperty:
Look for class: .*EnumProperty.*
Class Name |Objects |Shallow Heap |Retained
Heap |Perm
--------------------------------------------------------------------------------------------
org.apache.fop.fo.properties.EnumProperty$Maker| 94| 4'512|
|
org.apache.fop.fo.properties.EnumProperty | 182| 4'368|
|
Total of 2 entries | 276| 8'880|
|
--------------------------------------------------------------------------------------------
Then I noticed that NumberProperty (which uses the property cache)
has 98304 instances which couldn't be right. The problem: just using
that WeakHashMap isn't enough without the key objects implementing
hashCode() and equals() (see JDK javadocs). So I added an implementation
of the two methods to NumberProperty and here's what results:
After the change:
Look for class: .*NumberProperty.*
Class Name |Objects |Shallow
Heap |Retained Heap |Perm
-------------------------------------------------------------------------------------------------------
org.apache.fop.fo.properties.NumberProperty$Maker | 34|
1'632| |
org.apache.fop.fo.properties.NumberProperty | 10|
240| |
org.apache.fop.fo.flow.TableFObj$ColumnNumberPropertyMaker| 1|
48| |
Total of 3 entries | 45|
1'920| |
-------------------------------------------------------------------------------------------------------
Saves 2.3MB of memory for the instances of just one class!!!! What I
didn't look into is the penalty on performance, though. I can imagine
that could be quite a bit.
Here's the diff for the change:
Index:
C:/Dev/FOP/main/xml-fop-patching/src/java/org/apache/fop/fo/properties/NumberProperty.java
===================================================================
---
C:/Dev/FOP/main/xml-fop-patching/src/java/org/apache/fop/fo/properties/NumberProperty.java
(revision 557343)
+++
C:/Dev/FOP/main/xml-fop-patching/src/java/org/apache/fop/fo/properties/NumberProperty.java
(working copy)
@@ -217,4 +217,33 @@
return Color.black;
}
+ /** [EMAIL PROTECTED] */
+ public int hashCode() {
+ //Multiply by 100 to get better buckets for Double instances
+ return (int)(number.doubleValue() * 100);
+ }
+
+ /** [EMAIL PROTECTED] */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final NumberProperty other = (NumberProperty)obj;
+ if (number == null) {
+ if (other.number != null) {
+ return false;
+ }
+ } else if (!number.equals(other.number)) {
+ return false;
+ }
+ return true;
+ }
+
+
}
Food for thought...
Jeremias Maerki