Shadow Fields vs. Property Accessor Interface Round 2


If you guys haven’t noticed a (light-hearted) showdown between Dirk Lemmerman and me, let me quickly mention how we got to this point. For starters, Dirk created a JavaFX tip 23: “Save Memory Shadow Fields for Properties” to help application developers save memory when using JavaFX Properties. Pretty impressive knowing that you can save memory when objects aren’t needing to use JavaFX Property objects.

While looking at the code I couldn’t help but notice boilerplate code that drove me bonkers, so I decided to make a simple API that also took into account the interesting Shadow Fields pattern used by Dirk’s example. The API I created aka Property Accessor Interface comprises of default methods that easily allows developers to implement the interface as opposed to extending an abstract class to avoid Java’s single inheritance rule. To see the Property Accessor interface code I blog about it here. To my surprise Dirk created yet another blog entry to benchmark all three approaches. Below is the chronological order of the blog posts thus far if you are keeping up with all the fun.

  1. Save Memory Shadow Fields for Properties by Dirk Lemmerman
    Introducing the concept of Shadow Fields
  2. JavaFX Tips to Save Memory! Shadow Fields for Properties and Observables by Carl Dea
    My attempt to save memory and reduce boilerplate code.
  3. Shadow Fields vs. Property Accessor Interface by Dirk Temmerman
    A benchmark application to test the three approaches of objects having properties and raw datatypes for fields.
  4. Shadow Fields vs. Property Accessor Interface Round 2 by Carl Dea
    A revisit of the Property Accessor Interface to reduce the memory usage by centralizing a map of values.

As it turns out my implementation was the worst of the three even with the bloated object with already instantiated property fields according to post #3 above. 😦 Because I rushed into things and didn’t know the issue until Dirk’s post #3 above. Well, I’m not ready to wave the white flag and besides I still have a few tricks up my sleeve.

Next, you will get to see what I did to reduce the memory usage of the Property Accessor interface strategy. To see the code changes please see the code at the Github here. The only change I made was centralizing the Map containing the values. As you can see below the memory is much lower compared to Dirk’s post #3 above. However, event though I didn’t beat Dirk’s implementation using shadow fields I did slightly better than the standard object approach.

An updated Property Accessor Interface implementation using a centralized map.

An updated Property Accessor Interface implementation using a centralized map.

Conclusion

Although I’ve only made a simple change by removing the hash maps from every object and centralizing all values to a single map the Property Accessor interface still didn’t trim memory as low as the Shadow fields technique. I may explore other techniques such as weak references or take a look into memory mapped files. I doubt I can reduce things any further, but I believe a relatively small to medium application could use the Property Accessor interface to rapidly build apps. They (developers) could use proper pagination to avoid large lists. One last idea would be to create an annotation that could even reduce the boiler plate code.

Let me know ow what you think? Any suggestions?

Advertisements

3 thoughts on “Shadow Fields vs. Property Accessor Interface Round 2

  1. Marcel Heckel

    When you use arrays instead of the heavy HashMap you get memory usage of 144 MB (and with property beans 864 MB). Also the access time is better than with the HashMap.

    ———-

    package com.dlsc.profiling;

    import java.lang.reflect.Constructor;
    import java.util.ArrayList;
    import java.util.List;

    import javafx.beans.property.Property;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;

    /**
    * Provide default methods to support the similar capability of the shadow fields pattern. To save
    * memory object values don’t have to be wrapped into a Property object when using getters and
    * setters, however when calling property type methods values will be wrapped into a property
    * object.
    *
    * Default methods for Observable lists are provided too.
    *
    * Created by cpdea on 4/3/16.
    */
    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;
    }
    }

    default T refProperty(int name, Class propClass, Class rawValType)
    {
    Object p = getModelProperties()[name];
    Property prop = null;

    try
    {

    if (p == null)
    {
    Class[] constructorTypes = new Class[] { Object.class, String.class };
    Constructor propConstr = propClass
    .getDeclaredConstructor(constructorTypes);
    prop = propConstr.newInstance(this, String.valueOf(name));
    }
    else if (rawValType.isInstance(p))
    {
    Class[] constructorTypes = new Class[] { Object.class, String.class, rawValType };
    Constructor propConstr = propClass
    .getDeclaredConstructor(constructorTypes);
    prop = propConstr.newInstance(this, String.valueOf(name), p);
    }
    else
    {
    prop = (Property) p;
    }
    getModelProperties()[name] = prop;
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    return (T) prop;
    }

    default List getValues(int name, List defaultValue)
    {
    Object p, o = getModelProperties()[name];
    p = o;
    o = o == null ? defaultValue : o;
    if ( !o.equals(p))
    {
    getModelProperties()[name] = o;

    }
    return (List) o;
    }

    default void setValues(int name, List newList)
    {
    Object list = getModelProperties()[name];
    if (list == null || !(list instanceof ObservableList))
    {
    getModelProperties()[name] = newList;
    }
    else
    {
    // Should the list be totally replaced? below clears and adds all items
    ObservableList observableList = (ObservableList) list;
    observableList.clear();
    observableList.addAll(newList);
    }
    }

    default ObservableList refObservables(int name)
    {
    List list = (List) getModelProperties()[name];

    if (list == null)
    {
    list = FXCollections.observableArrayList(getValues(name, new ArrayList()));
    getModelProperties()[name] = list;
    }

    if ( !(list instanceof ObservableList))
    {
    list = FXCollections.observableArrayList(list);
    getModelProperties()[name] = list;
    }

    return (ObservableList) list;
    }
    }

    ———————

    package com.dlsc.profiling;

    import java.util.ArrayList;
    import java.util.List;

    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
    import javafx.collections.ObservableList;

    /**
    * A hybrid domain and model object using the shadow field pattern to save memory. Created by cpdea
    */
    public class EmployeePropertyAccessor implements PropertyAccessors
    {

    private final Object[] modelProperties = new Object[4];

    public static final int NAME_PROPERTY = 0;

    public static final int POWERS_PROPERTY = 1;

    public static final int SUPERVISOR_PROPERTY = 2;

    public static final int MINIONS_PROPERTY = 3;

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

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

    public final String getName()
    {
    return getValue(NAME_PROPERTY, “”);
    }

    public final void setName(String name)
    {
    setValue(NAME_PROPERTY, name);
    }

    public final StringProperty nameProperty()
    {
    return refProperty(NAME_PROPERTY, SimpleStringProperty.class, String.class);
    }

    public String getPowers()
    {
    return getValue(POWERS_PROPERTY, “”);
    }

    public final StringProperty powersProperty()
    {
    return refProperty(POWERS_PROPERTY, SimpleStringProperty.class, String.class);
    }

    public final void setPowers(String powers)
    {
    setValue(POWERS_PROPERTY, powers);
    }

    public final EmployeePropertyAccessor getSupervisor()
    {
    return getValue(SUPERVISOR_PROPERTY, null);
    }

    public final ObjectProperty supervisorProperty()
    {
    return refProperty(SUPERVISOR_PROPERTY, SimpleObjectProperty.class,
    EmployeePropertyAccessor.class);
    }

    public final void setSupervisor(EmployeePropertyAccessor supervisor)
    {
    setValue(SUPERVISOR_PROPERTY, supervisor);
    }

    public final List getMinions()
    {
    return getValues(MINIONS_PROPERTY, new ArrayList());
    }

    public final ObservableList minionsObservables()
    {
    return refObservables(MINIONS_PROPERTY);
    }

    public final void setMinions(List minions)
    {
    setValues(MINIONS_PROPERTY, minions);
    }

    }

  2. Pingback: Shadow Fields vs. Property Accessors Interface Round 3 | CarlFX Blog

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s