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