When I refactored FlexibleStringExpander.java a while ago (rev 687442),
there were things I wanted to improve but couldn't - because I wanted to
maintain backward-compatibility.
Adam's recent memory-saving efforts reminded me of one of the things I
wanted to change in FlexibleStringExpander.java - I wanted to make the
object more lightweight.
OFBiz can hold anywhere from tens of thousands to hundreds of thousands
of these objects in memory, so an object size reduction could be beneficial.
With that under consideration, I would like to do a little more work on
the class. What I have in mind is to keep the existing API the same - to
preserve backward compatibility - but add an interface so that we can
make gradual changes to framework code that will improve memory use.
Here are the changes I have in mind:
1. Extract an interface from FlexibleStringExpander, call it something
like StringExpression.
2. Convert FlexibleStringExpander to an abstract class that implements
StringExpression.
3. Have FlexibleStringExpander's nested classes extend
FlexibleStringExpander.
4. Reduce object size by having each FlexibleStringExpander subclass
contain only the objects it needs.
This is an initial step - nothing changes from the API point of view. No
changes would need to be made to framework code.
As time and resources permit, we can gradually change lines like:
FlexibleStringExpander fse = FlexibleStringExpander.getInstance(expression);
to:
StringExpression se = FlexibleStringExpander.getInstance(expression);
and both versions will work the same.
After all FlexibleStringExpander instances have been replaced with
StringExpression instances, we can extract the FlexibleStringExpander
nested classes into individual files, have them implement
StringExpression, and remove the class extension. FlexibleStringExpander
then becomes nothing more than a factory and some static convenience
methods.
That's it. If you want to know how this will benefit memory use, read on...
Consider this mini-language statement:
<set field="isTrue" value="Y"/>
The value attribute is kept in memory as a FlexibleStringExpander
instance. That instance will contain one instance of ConstElem that
contains the String "Y". So, let's tally up the memory used for this
single character:
FlexibleStringExpander fields:
String orig = "Y"
List strElems = a List with one ConstElem element
int hint = 20 (used as a StringBuilder initial size)
ConstElem fields:
String str = "Y"
That's a lot of overhead to store a single character. After the proposed
refactor, the value attribute will be kept in memory as a ConstElem
instance - which will contain nothing more than the String "Y".
The ConstElem class really doesn't need the String class methods, so we
can eliminate the String instance too - by storing it as a character
array. Now the "Y" StringExpression instance takes up the same space as
a String object.
What do you think?
-Adrian