javafx.scene.shape.Path (memory) inefficient PathElements

Jim Graham james.graham at oracle.com
Thu May 4 21:33:37 UTC 2017


Hi Tom,

Those look like good suggestions.  I would file bugs in JBS and create them separately:

- Bug for lazy property creation in path elements
- Feature request for lower-memory paths

Did you benchmark how much the lazy properties, on their own, would save your application?

				...jim

On 5/4/17 2:22 PM, Tom Schindl wrote:
> Hi,
>
> We are currently working on a PDF-Rendering library in JavaFX and we
> need to draw glyphs using the JavaFX Path API (there are multiple
> reasons why we don't use the Text-Node and or Canvas).
>
> When drawing a page full of Text this means that we have a Path-Object
> with gazillions of MoveTo and CubicCurveTo elements who sum up to 30MB
> just to represent them in the SG because PathElements store their
> information in properties and forcefully intialize them in their
> constructor.
>
> The only public API to work around this problem is to construct a
> StringBuffer and use SVGPath which means:
> * it takes time to construct the SVG-Path-String
> * it takes time to parse the SVG-Path-String in JavaFX
>
> As an experiment (and because we are still on Java8 we can easily do
> that) was that we created our own Shape-Subclass who:
> * uses floats (there's no reason to use double in the SG when the
>   backing API - Path2D - is float based)
> * passes the floats directly to the Path2D/NGPath API
>
> Guess what: We now need 2.5MB / page which means 27.5MB is the overhead
> added by the current Path-API - ouch!
>
> I think a fairly low hanging memory optimization for the PathElement
> would be to create properties lazy (only if someone access the property).
>
> For MoveTo this would mean the following minimal change (eg for the
> x-value):
>
> private DoubleProperty x;
> private double _x;
>
> public final void setX(double value) {
>   if (x != null) {
>      xProperty().set(value);
>   } else {
>      _x = value;
>      u();
>   }
> }
>
> public final double getX() {
>   return x == null ? _x : x.get();
> }
>
> public final DoubleProperty xProperty() {
>   if (x == null) {
>     x = new DoublePropertyBase(_x) {
>
>       @Override
>       public void invalidated() {
>         u();
>       }
>
>       @Override
>       public Object getBean() {
>         return MoveTo.this;
>       }
>
>       @Override
>       public String getName() {
>         return "x";
>       }
>    };
>   }
>   return x;
> }
>
> I guess 99% of the code out there never access the Property so the small
> footprint added by the primitive field is justifiable.
>
> This still has the overhead of all the needless PathElement objects
> hanging around so another idea is to have a 3rd SG-Path-Type who
> strictly uses the float-Primitives with a similar API to Path2D (in fact
> it only acts as a public API to Path2D).
>
> Thoughts?
>
> Tom
>


More information about the openjfx-dev mailing list