JavaFX Tip 23: Save Memory! Shadow Fields for Properties
Properties and property bindings introduced in Java 8 are extremely useful programming concepts. They are especially useful when you are developing user interfaces. In fact they are so useful that developers have fallen victim to the idea that everything should be a property instead of a primitive. Unfortunately they easily forget that properties such as SimpleLongProperty are much bigger objects than standard types such as Long. And of course they are much bigger than primitive data types such as long.
In one of my current projects pretty much every model object used by the client is composed of properties. For many of these model objects it is the right approach because they will be edited / modified via JavaFX controls. But there are also many model objects that are not edited. They exist to support the rendering of schedules in the FlexGanttFX control. These objects do not need to be observed, hence they do not need to provide properties … but they do and they waste a lot of memory because they do.
One way to fix this would be to refactor the model classes and to get rid of all properties, but then again we might want to use these objects in a future release in a different context and then we might need properties because we want to edit them directly. What to do?
Shadow Fields
The solution to this problem is something I recently saw Gerrit Grunwald do in the code of his Medusa project and a pattern that was described by Mr. Properties himself Michael Heinrichs. The pattern makes use of a “shadow field” that is of the same type as the wrapped object inside the property. When using this pattern a property will only be created when it is really needed (“when somebody asks for it”).
Example
In this example we want to manage an attribute called “title”. We need a setter, a getter, and the property accessor.
private String _title = "Untitled"; // shadow field private StringProperty title; public final String getTitle() { title == null ? return _title : title.get(); } public final void setTitle(String newTitle) { if (title == null) { _title = newTitle; } else { title.set(newTitle); } } public final StringProperty titleProperty() { if (title == null) { /// !!!! pass shadow field to constructor title = new StringProperty(this, "title", _title); } return title; }
By using this pattern I was able to bring down the memory footprint from 310 MB to 250 MB for a specific use case in my project. The saved memory is ten times the total memory my computer had when I was a student. Just think about that!
Reference: | JavaFX Tip 23: Save Memory! Shadow Fields for Properties from our JCG partner Dirk Lemmermann at the Pixel Perfect blog. |