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.
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.