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:

  1. standard properties that are instantiated at the same time when the class gets instantiated
  2. property accessor interface as proposed by Carl
  3. 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):

A1

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.

A2.png

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.

6 Comments

  1. Using these so-called ‘Shadow fields’ is just a cheap trick to reduce the initial memory consumption of your program. When you really use all functions, the memory consumption is even higher, and the performance is worse (Shadow fields must be held and handled).

  2. It is not a cheap trick, but you are right, you end up with two references. Solution: simply set the shadow field to null when the property gets created. Example:

    public final StringProperty nameProperty() {
    if (name == null) {
    name = new StringProperty(this, “name”, _name);
    _name = null; // free memory
    }
    return name;
    }

  3. No matter how you call it, it won’t save you any memory at all: After having accessed all properties, you end up with at least the same amount of used memory than before – everything else would just mean you have declared properties without the need for them (which in result would mean you have to re-think your software’s architecture).
    A feasible solution for the memory usage problem could be to only instantiate the properties that are needed in the current view of your program and not all properties that are needed anywhere in your program at once… With this approach you would use Java effectively and let the garbage collector do it’s work.

  4. Correct, “after having accessed all properties” you end up with the SAME memory allocation. But this is exactly what doesn’t always happen, especially when using a third party library. Take the Medusa library for example. Most applications will call a bunch of setter methods to customise the colors of those controls and then they are done with it. No need for properties. Other applications however might want to make the colors depend on certain conditions. These apps would need properties for binding purposes.

    However the shadow field pattern is most useful for model classes, not necessarily single controls. Imagine an application that loads one thousand “Person” entities with first name, last name, and address information. The UI shows the “Person” entities in a TableView, but only the first and last name. Then the TableView will use only those two properties. Only when the user selects a person then the address of that person will be shown in a detail view and only then properties such as “city”, “zip code”, “street” will be used and bound. It is not very likely that the user will look at the details of all (one thousand) “Person” entities. So imagine he edits 10 of them. Then we have 990 entities times (guessing) 5 properties hat are never used. That is a lot of wasted memory.

    By the way, the “feasible” solution that you mention in your last comment …. this is exactly what the shadow field pattern does.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s