Desktop Java

Shadow Fields vs. Property Accessors Interface Round 3

This is round 3 of the Shadow Fields vs Property Accessors Interface. If you are new and not sure what the fuss is about please check out my previous post or my first post on the topic of saving memory when developing JavaFX applications. As a Java developer my main concern is having a good balance between performance, memory usage and lowering boilerplate code (ease of API use) when developing JavaFX domain models. Usually, application frameworks provide a model view controller(MVC) or presentation model pattern to separate UI code from domain objects. In fact what comes to mind is that domain model type objects should be easy to create or generated (IDEs). In this blog entry you will see results of Round 3 with two parts. Part 1 was implemented using an idea from Marcel Heckel and Part 2 is an implementation that I eventually settled with based on performance, memory usage and ease of use.

  • Disclaimer: Use any of the code at your own risk. This is purely experimental and should not be used in production. This is a work in progress.

The latest code is here —> [PropertyAccessors interface]

Recap of Round 2

Although, the last round (round 2) indicated that my Property Accessors strategy was slightly better in memory consumption than the standard (fat) property objects strategy, it was still disappointing in terms of performance when creating 2,000,000 objects of an Employee type class having native type objects. I still was not happy with the memory usage of my round 2 implementation compared to Dirk’s implementation. If you just care about my final results of Round 3 just skip to the Results section.

Because, there might be a new Round please check out the current code here  if you decide to use it or assuming Dirk decides to accept my pull request head over to his Github account here.

In round 2, I used a hash map lookup that can be quite slow as more and more fields are added with a O(1) time complexity (search). Interestingly, Marcel Heckel commented to suggest a simple approach of creating an indexed array of objects which will not not only save more memory but will be much faster. Compared to a key/value pair lookup a direct index access to a field is definitely the way to go. Although, Marcel’s code is faster, it still takes up more memory than Dirk’s Shadow Fields code. The extra memory is actually taken up by the preallocating of an array that will hold the values for the each field. Even if they are all nulls the array itself is created for each employee object. I implemented Marcel’s strategy here (line 23). Let’s look at the results of the array of indexed fields strategy.

Part 1: Using an Array of Indexed Fields

private final Object[] modelProperties =
                               new Object[FIELDS.values().length];
    public Object[] getModelProperties(){
        return modelProperties;
    }

TEST: Objects Not Using Property Fields

Shown below is using a mix of Marcel’s indexed array idea and my way of specifying the property name using enum types to denote fields as property fields.

screen-shot-2016-04-07-at-12-18-01-am
Objects that aren’t using JavaFX properties compared to standard (fat) objects with all fields as JavaFX properties. This implementation uses an array index for each field and an array to hold each value.

Above you will notice the check box is unselected to indicate not to create JavaFX properties on the domain object (not using the xxxxProperty() methods). You’ll notice that the performance has dramatically increased compared to round 2’s code and memory usage also reduced. In the figure above the Property Accessor interface is at 16MB more than the Shadow Fields’ pattern implementation. In part 1 of thin objects performance and memory usage Shadow Fields is the clear winner. However, Shadow Fields is still not as clean to implement. Another thing to note is that Property Accessors interface is just shy of 14 milliseconds for 2 million objects! As we’ll see later in Part 2 Bringing back Private Instance Variables as Fields the Property Accessors interface will really shine with memory usage.

TEST: Objects Using of Property Fields

The following is the results when all fields of an object is using JavaFX properties.

screen-shot-2016-04-07-at-12-24-22-am
Objects that are using JavaFX properties compared to standard (fat) objects with all fields as Javafx properties. This implementation uses an array index for each field and an array to hold each value.

Here, you’ll notice the Accessor columns (Property Accessors interface) at 2 million objects performs at 916 milliseconds with a 576 MB use of memory. In this case the standard (fat) object is the winner as far as memory space at 544 MB. Shadow Fields wins on performance on every round so far.

One minor detail with Marcel’s code example (in the comments section) is it doesn’t take into account the string name of the property when creating a new property object instance. For example the following statement shows the variable totalProperty with the property named ‘total‘ which matches the totalProperty() method. Firing the name of a property during change is important for reading code, testing and tooling.

Property totalProperty = new SimpleIntegerProperty(this, “total”, new Integer(5));

To have both a named field and an index like Marcel’s idea, I simply created an enum declaring each field property. These enums are created on the Employee class.

// Part 1 implementation
public class EmployeePropertyAccessor implements PropertyAccessors{
    public enum FIELDS {
        name,
        powers,
        supervisor,
        minions
    }
    private final Object[] modelProperties =
                               new Object[FIELDS.values().length];

    public Object[] getModelProperties(){
        return modelProperties;
    }

    // The rest of the code...

Above you will notice how the model Properties array will be created based on the number of defined fields (enum FIELDS). I use the FIELDS.value().length to define the size of the array. Also, the PropertyAccessors interface (Part 1’s implementation) forces the developer to implement the getModelProperties() method. Here, I just returned the modelProperties‘ reference to an array of objects. It isn’t very pleasant to ‘have to‘ implement an array and a getModelProperties() method .

In part 2, of this article, I implemented things differently where the developer isn’t forced to implement a modelProperties array and a getModelProperties() method. I will solve this issue where the code will look much cleaner and performant (user of the API’s perspective).

Part 2: Reintroducing Instance Variables

Part 2, I will be adding private instance variables back into the Employee class (EmployeePropertyAccessor) to hold the field values instead of an array like in Part 1. My idea was to have a field variable be mutually exclusive to either point to a native object type or a JavaFX property, thus saving memory compared to the Shadow Field pattern code. Since, the Shadow Fields code uses two variables to represent a field value, it will have an extra reference which will inevitably increase its memory when the object uses properties. As you can see below the code will look similar to part 1, but also will have a static block to register the property fields in the class. This is important because some instance variable you may not want participate as JavaFX properties.

// Part 2 implementation
public class EmployeePropertyAccessor implements PropertyAccessors {

    private Object name;
    private Object powers;
    private Object supervisor;
    private Object minions;

    enum FIELDS {
        name,
        powers,
        supervisor,
        minions
    }

    static {
        // register fields one time.
        // (Warning: enum's ordinal value is reassigned an index number)
        registerFields(EmployeePropertyAccessor.class, FIELDS.values());
    }

    public EmployeePropertyAccessor(String name, String powers) {
        setName(name);
        setPowers(powers);
    }

    public final String getName() {
        return getValue(FIELDS.name, "");
    }
    public final void setName(String name) {
        setValue(FIELDS.name, name);
    }
    public final StringProperty nameProperty() {
        return refProperty(FIELDS.name,
SimpleStringProperty.class, String.class);
    }

    // The rest of the code...

The code listing above does some interesting magic when calling the registerFields() method. The FIELDS enums’ ordinal values are reassigned using reflection giving each a new id as an index into an array. This provides immutable enums while also containing a unique identifier for each field to be accessed fast via an index. Since enum are used to represent fields to be used as properties, the ordinal values are meaningless in other contexts. This means: Who cares, if the ordinal value is reassigned on these declared enums? They are only used for this purpose only ‘to register fields‘.

TEST: Objects Not Using Property Fields [NEW]

Shown below is the test results using the new implementation of the Property Accessors interface API. The test below shows when not using property fields compared to the standard fat object.

A test that compares standard objects (all fields using properties) vs objects using native objects. Property Accessors interface API now uses instance variables as fields instead of a reference to an array.
A test that compares standard objects (all fields using properties) vs objects using native objects. Property Accessors interface API now uses instance variables as fields instead of a reference to an array.

As you can see above the new implementation of the Property Accessors interface is the clear winner for memory usage and ease of use. The performance is slightly slower than part 1’s implementation but the savings in memory is worth it. You’ll notice that the Shadow Fields’ memory usage is 16 MB more than Property Accessors’ usage.

TEST: Objects Using of Property Fields [NEW]

Shown below is the test results using the new implementation of the Property Accessors interface API. The test below shows when using property fields compared to the standard fat object. (The check box is checked underneath the Start button)

screen-shot-2016-04-09-at-12-36-02-pm

Results of Round 3

Below are bar charts I threw together based on the results in the tables. I felt people like to see charts instead of tables, cells and text.

performance_a
Test results of performance when objects aren’t using JavaFX properties. Smaller number (in milliseconds) is better.

performance_b
Test results of performance when objects are using JavaFX properties. Smaller number (in milliseconds) is better.

memusage_a
Test results of memory usage when objects are not using JavaFX properties. Smaller number (in megabytes) is better.

memusage_b
Test results of memory usage when objects are using JavaFX properties. Smaller number (in megabytes) is better.

Conclusion

Based on the results my goal was definitely achieved (IMHO) where I originally wanted code to be simple to read and easy to implement when objects may or may not use JavaFX properties (with the added benefit of saving memory when fields aren’t using JavaFX properties [native types]). Although, performance-wise Shadow Fields won on all of test runs, Property Accessors interface wasn’t far behind. When not using properties Property Accessors interface  beats the Standard object strategy by a mere 5 milliseconds when creating 2 million records.

When it comes to memory usage with creating 2 million objects and when the strategies were  not using properties as fields, the Property Accessors interface is clearly the winner with a savings of at least 16MB compared to the Shadow Fields pattern and a 240MB savings compared to the Standard Properties code. Last, but not least is the results when objects are using properties as fields, Property Accessors interface ties with the Standard objects strategy regarding memory consumption. The Shadow Fields strategy uses is at least 20MB more than the other strategies.

Even though Properties Accessors interface is slightly slower (by a small difference in milliseconds) when using or not using all fields as properties for 2 million objects, I am convinced the API can be used on any JavaFX application size for the ease of development of domain models and objects. I encourage others to test the code themselves before making the decision to use the API. Please be advised that the code isn’t considered production ready and is very experimental. This is a work in progress, so until I get to eat my own dog food (at work) I can’t really recommend that you use the Property Accessors API. I’ll restate the disclaimer below:

  • Disclaimer: Use any of the code at your own risk. This is purely experimental and should not be used in production. This is a work in progress.

Feel free to comment and subscribe. Enjoy and happy coding!

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Marcel Heckel
Marcel Heckel
8 years ago

Hi, really nice idea. But in some environments the SecurityManager may restrict the changing the ordinal value of the enum. Also the performance tests only include the creation of the objects. The time to access the method should also be measured. E.g.: private static int ACCESS_COUNT = 100; … for (int j = 0; j < ACCESS_COUNT; j++ ) { String t = employee.getName(); employee.setName(employee.getPowers()); employee.setPowers(t); } In general, refection is slower than direct access to the methods. I did some test regarding time performance, but the Just In Time compiling was interfering the results every time in a different… Read more »

Carl Dea
8 years ago

Mark,
Thanks again, for the suggestions.
I actually did that before I did reflection. Simple, seems to mostly beat out more complexity. Another idea might be the use of the compiler API. I bet security will be a road block for that also.

My intent was to have a good balance for the user of the API. ;-)

Carl

Marcel Heckel
Marcel Heckel
8 years ago
Reply to  Carl Dea

OK.
But you are right: Generating the code at runtime with Javassist would be probably the fastest solution.
Marcel

Back to top button