[External] : Re: Experiment: Node properties

John Hendrikx john.hendrikx at gmail.com
Thu Feb 26 00:29:50 UTC 2026


You could look into the com.sun.javafx.css.FixedCapacitySet code I wrote
before. It features:

- Single and dual entry versions (very fast and a common case I suppose
for what you are proposing)
- Array version without hashing (up to a tunable number of elements, 10
I believe)
- Open addressed hash version (uses an array, not Map.Entry), very low
memory use for a hash table, unlimited elements, O(1) performance,
faster than HashMap (HashMap shines in write performance, which we don't
really need here).
- Relatively simple implementation because it is read-only (no
add/remove or restructuring logic needed).

All that you'd need to do is make a Map version of it, and do a "copy on
write" approach if a property needs adding (which should be rare, and
should eventually stop occurring, so one can basically ignore that cost).

Main benefit is that this will perform really fast for the most likely
cases, and "degrades" to map-like O(1) performance with a hash.  This
lowers the barrier for adding even more properties, even if a bit more
commonly used.

Hashing will be fast as we're talking about properties, which have no
hashCode/equals implementation, so you get the default.

If you want I could adapt it to be a map, and to have "copy on write"
semantics.

--John

On 25/02/2026 21:25, Andy Goryachev wrote:
> John brings a good point about effects on performance, and no amount
> of explanation from both sides of the argument are going to help.  I
> believe the performance of small arrays will be surprisingly better
> than a hash table, but the only way to resolve this question is to
> measure.  I am planning to test it and will certainly share the results.
>
> If you are willing to try it out, you could run your app with jfx
> build from the branches mentioned earlier (I've synced them up with
> the latest master).
>
> To measure the heap consumption changes, you can use VisualVM, make
> sure to set FastMap.COLLECT_STATISTICS to false.  With statistics
> enabled, you'll see some stdout but those are just estimates, so
> I wouldn't trust them much.
>
> Measuring the impact of performance is more difficult.  One test that
> might get /some/ idea is to time the startup of the app, since it
> involves massive creation of Nodes, application of CSS, and many other
> things in a burst.  It's probably best to launch several times and
> pick the best time, to reduce the effect of disk caches etc.
>
> Also, keep in mind that, theoretically, there are more properties that
> can be classified as "rare", so we might see even more improvement
> should we deem this idea worthwhile.
>
> Another benefit is that it will be easier to add convenience
> properties instead of constructing Subscription chains.
>
> Let us know what you find out.
>
> Thanks,
> -andy
>
>
>
> *From: *Marius Hanl <mariushanl at web.de>
> *Date: *Wednesday, February 25, 2026 at 11:01
> *To: *john.hendrikx at gmail.com <john.hendrikx at gmail.com>, Andy
> Goryachev <andy.goryachev at oracle.com>, openjfx-dev at openjdk.org
> <openjfx-dev at openjdk.org>
> *Subject: *Re: [External] : Re: Experiment: Node properties
>
> This Message Is From an Untrusted Sender
> You have not previously corresponded with this sender.
> Report Suspicious
> <https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!P92y3kIlEUDHNjoglxNe8W35-VFyXSOZUhFd19FhWbbhvLXCLQjEuwQjFsPmBDAC5oo8MYkWp56ID_EXmbsVoEXn0ha_sPZIVqpwHIWOUGbDNs5chWugVxtHCnuulc1NfT37q6FfJ5sJIeXiGHyBMy8FywkueD6HBh2Z2lgRphe1M3LGN5uSITi0$>
>  
> I also agree with John here. Especially regarding the lookup, we
> should definitely use a hash based algorithm (HashMap?) with a
> reasonable default size.
> hashCode really is not expensive, but we should recheck. 
>  
> @Andy, when you did the changes / rechecked, I would be happy to test
> it with some applications.
> I usually set the compact object headers in those applications as
> well, so we will see how much we gain then. If there is something I
> should use or do (VisualVM?), just tell me to do so. I'm interested as
> well about the gains.
>  
> Marius
>  
>  
> *Gesendet: *Dienstag, 24. Februar 2026 um 08:05
> *Von: *"John Hendrikx" <john.hendrikx at gmail.com>
> *An: *"Andy Goryachev" <andy.goryachev at oracle.com>,
> "openjfx-dev at openjdk.org" <openjfx-dev at openjdk.org>
> *Betreff: *[External] : Re: Experiment: Node properties
>
> Thanks for the taking the time to respond.
>
> On 24/02/2026 00:32, Andy Goryachev wrote:
>
>     > What trade off are you making here?  It seems we're trading a
>     small memory gain for more CPU use (extra indirection, walking a
>     list linearly to find the correct property on each use/access VS
>     no indirection, no list walking).
>
>      
>     You are right.  The tradeoff is non-zero memory gain (a few
>     megabytes, to the tune of maybe 5% of total heap size) at the cost
>     of extra CPU cycles.  The rationale is that even though we consume
>     extra CPU, it's much less noticeable because of the cache-friendly
>     implementation and non-zero positive impact on garbage collector
>     (less memory to scan).
>
> What is more cache friendly about adding several extra indirections to
> get to a property's value?  Let me see:
>
> Before:
>
> - isFocusTraversable(): get property -> get value
>
> After:
>
> - isFocusTraversable(): get fast map -> get key ArrayList -> get
> internal array -> get value ArrayList -> get internal array -> get
> property -> get value
>
> For the garbage collector, the properties are likely going to be in an
> area of the GC collector that will be scanned rarely, and not part of
> the frequent scans for young objects. I don't think we can generally
> conclude that having less memory used will have an overall positive
> impact on the GC here.  The properties will be seen as long-lived by
> the GC, and will reside in an area only scanned rarely, which has very
> little impact on the performance of most GC implementations.  
>
>      
>      
>
>     > Are the resource constrained platforms you named generally memory
>     or CPU constrained?
>
>      
>     I asked Gluon for some feedback on iOS/Android.  However, my
>     previous experience with a large trading application says that
>     memory footprint savings outweighs the CPU cycles, so I would
>     imagine we'll get a net gain even on the desktop.
>
> That's anecdotal, and will depend on the type of application,
> platform, CPU cores available, etc.  So while you may be correct for
> your trading application, it may be completely the opposite for a task
> tracking application. In general, memory use is hardly a factor for
> most applications; most Java apps don't even bother to limit the heap,
> yet complain about several GB's of memory use when they have a
> retained size of less than half a GB.  Not that I'm not in favor of
> reducing memory footprint, but I seriously wonder if there is much to
> gain at the property level.
>
>  
>
>      
>      
>
>     > Have you investigated a breakdown of JavaFX memory use, and did
>     the amount of memory used by properties come out on top here?
>
>      
>     There is some statistics provided in
>     https://github.com/andy-goryachev-oracle/Test/blob/main/doc/Experiments/NodeProperties.md ,
>     please take a look.
>
> I took a look, but could only find statistics about properties. I
> didn't see a breakdown of general JavaFX memory use (the other 95%) to
> see if properties are the lowest hanging fruit.
>
>      
>      
>
>     > Would the gains you made here become irrelevant or less relevant
>     with Compact Object Headers [https://openjdk.org/jeps/519]
>
>      
>     Compact Object Headers are almost irrelevant here - the stats that
>     were collected count the number of pointers saved (assumed 8 bytes
>     per pointer on 64 bit).  The stats ignore any other possible savings.
>
> Compact Object Headers is especially relevant here as you're
> optimizing small objects (properties) on which JEP519 offers the most
> relative gain.  Enabling it may reduce the 5% memory gain you measured
> to a smaller margin, which impacts the rationale for this change.
>
> Furthermore, if we're talking about saving memory, I think we can
> assume we're using small heaps (less than 32 GB).  In that case,
> Hotspot will use 4 bytes per pointer (compressed OOPs) not 8, so your
> assumption of 8 bytes per pointer will be incorrect in the vast
> majority of JavaFX cases.
>
>      
>      
>
>     > I think the property look-up system cannot reasonably be List
>     (FastMap despite its name is a List). Converting this to a map
>     however is likely to require a small object (like Map.Entry) which
>     will further reduce any gains you made here I think.
>
>      
>     The FastMap is a map-like (key-value) storage, even though it's
>     implemented as an array.  There is a debate as to what would the
>     most efficient implementation entail (a hashmap, one array, or two
>     arrays like the POC currently uses).  The idea is not to put
>     *all*​ the properties into the container, but only the rarely used
>     ones, with the end result of having a few (less than 4-6, say).
>      This makes the object small and cache-friendly, which further
>     speeds up the access.
>
> I'm aware of the intentions to only put the rarely used properties
> there.  What is rarely used will depend on the application.  How many
> properties will end up being stored there also depends on the
> application.  What if the app does need several of these properties
> and this structure grows to contain 20-30 properties?
>
> Currently your proposal wants to store these rarely used properties in
> an O(n) structure, whereas a hash based solutions are O(1), and where
> doing nothing is even faster as there is no map at all.
>
> So although your map implementation may be small and cache friendly
> (that last point being debatable, see indirection count), it degrades
> badly when there are more than the predicted amount of properties, and
> requires many more indirections than the base case of doing nothing.
>
> There is talk about not having to do an expensive `hashCode` call in
> your proposal.  First, `hashCode` is really cheap for objects not
> implementing equality as it falls back on the Object#hashCode.  I
> believe this is the case for properties.  Even if it isn't the case,
> you could use the identity hash code here (the `==` equivalent in the
> hashing world).
>
> However that "expensive" call is what enables the O(1) lookup of the
> value you are interested in, which can be truly cache friendly with
> the right structure (array based open addressed map).
>
> --John
>
>      
>      
>     Thanks!
>      
>     -andy
>      
>      
>      
>      
>      
>     *From: *openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf of
>     John Hendrikx <john.hendrikx at gmail.com>
>     *Date: *Thursday, February 19, 2026 at 15:28
>     *To: *openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
>     *Subject: *Re: Experiment: Node properties
>
>      
>
>     On 04/02/2026 22:17, Andy Goryachev wrote:
>
>         I would like to share the results of a little experiment
>         involving optimization of storage of Node properties.  The
>         basic idea is to create a compact fast map-like container to
>         hold the rarely instantiated properties in order to reduce the
>         application memory footprint.
>          
>         The savings are not overwhelming, but not exactly zero.  I
>         would imagine this optimization might be more interesting in
>         any resource constrained environment such as Android / iOS /
>         RaspberryPi.  Please refer to [0] for the details.
>
>     What trade off are you making here?  It seems we're trading a
>     small memory gain for more CPU use (extra indirection, walking a
>     list linearly to find the correct property on each use/access VS
>     no indirection, no list walking).
>
>     Are the resource constrained platforms you named generally memory
>     or CPU constrained?
>
>     Have you investigated a breakdown of JavaFX memory use, and did
>     the amount of memory used by properties come out on top here?
>
>     Would the gains you made here become irrelevant or less relevant
>     with Compact Object Headers [https://openjdk.org/jeps/519]
>
>      
>
>          
>         I encourage you to try it with your application, to see
>         whether you notice any change in memory consumption and/or
>         performance.  Let me know what you think!
>
>     I like the idea, but I wonder if there really is much to gain
>     here, and whether those gains will hold up with future Java
>     improvements.
>
>     I think the property look-up system cannot reasonably be List
>     (FastMap despite its name is a List). Converting this to a map
>     however is likely to require a small object (like Map.Entry) which
>     will further reduce any gains you made here I think.
>
>     --John
>
>          
>         Cheers,
>         -andy
>          
>          
>         *References*
>          
>         [0]
>         https://github.com/andy-goryachev-oracle/Test/blob/main/doc/Experiments/NodeProperties.md
>          
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20260226/355556d1/attachment-0001.htm>


More information about the openjfx-dev mailing list