Shadow Fields vs. Property Accessor Interface
Carl Dea recently followed up on a blog post of mine called Save Memory! Use Shadow Fields for Properties. In his blog he suggested the use of an interface called “Property Accessor” to eliminate the heavy use of boilerplate code that is needed in order to use shadow fields. Carl also mentioned that he hasn’t tested his approach with a lot of data and that he or some reader might follow up with a performance comparison. So here it comes.
I wrote a small test application that implements the three strategies that Carl mentions in his post:
- standard properties that are instantiated at the same time when the class gets instantiated
- property accessor interface as proposed by Carl
- shadow fields as proposed in my recent blog post
The code can be found on GitHub. (when you run it please make sure to set the initial and the maximum heap size to 2048 MB -ms2048m -mx2048m, otherwise the memory allocations will mess up the results).
The application allows the user to execute these strategies either with or without asking for the properties. It measures the time spent and the memory used. It should be noted that the measurements are not scientific as I used System.currentTimeInMillis() and Runtime.gc(). When run several times I would still argue that the qualitative value of these tests are acceptable.
The first screenshot below shows the numbers you get when you create between 1,000 and 2,000,000 instances of the Employee class that Carl used for his blog. The tests do not ask for the properties that are available on Employee (name, powers, supervisor, minions):
As you can see the “shadow field” strategy is the fastest and also uses the least amount of memory. This makes sense as the “standard properties” strategy always creates those fat property objects and the “property accessor interface” internally manages a hash map for each model object. Only the “shadow field” strategy works with a minimal amount of data structures. In the case of the selected test it saves a total of 230 MB. If you now imagine that typical applications have many model classes and many of those much more complex than the Employee test class then you can imagine how much memory you can save.
The next screenshot shows the measurements taken when also accessing all four properties and observables inside the Employee class.
Now the “standard properties” strategy is the fastest and also the one that uses the least amount of memory. Once again, this makes sense, as this strategy now implements the perfect approach for the given use case. However, the “shadow field” strategy comes in at a very close 2nd place.
Conclusion
The “Property Accessor Interface” strategy is successful at reducing the noise created by all the boilerplate code needed for shadow fields but it comes at a price that I believe is too high to pay for any application that creates more than just a few model objects.
P.S.: it should be noted that the comparison is even more in favour of the “shadow fields” strategy when the initial heap size of the JVM is left at its default setting. In this case the test app has to keep asking for more heap space which is quite an expensive operation.
Reference: | Shadow Fields vs. Property Accessor Interface from our JCG partner Dirk Lemmermann at the Pixel Perfect blog. |
How about using an array instead of a heavy HashMap in Property Accessor? This should reduce the memory consumption… —————– public interface PropertyAccessors { Object[] getModelProperties(); default T getValue(int name, Object defaultVal) { Object p = getModelProperties()[name]; p = p==null ? defaultVal : p; return (T) ((p instanceof Property) ? ((Property) p).getValue(): p); } default void setValue(int name, Object value) { Object p = getModelProperties()[name]; if (p instanceof Property) { ((Property)p).setValue(value); } else { getModelProperties()[name] = value; } } … } —————– public class Employee implements PropertyAccessors{ private Object[] modelProperties=new Object[4] ; public static final int NAME_PROPERTY = 0; public… Read more »
@Marcel Baumann Heckel that sounds like an interesting idea, but you would need to leave that comment on Carl’s blog as he “represents” the PropertyAccessor team :-)
Marcel,
I like that idea. I think there are still two indexed ways to avoid a dictionary lookup. I will give things a try and post another round. Last round I found a bug that failed on the lists and PropertyObjects. Round 2 wasn’t complete because of a bug for fat objects.
For the fat objects (from round 2) assuming the bug fixes I believe my strategy might beat shadow fields.