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 <[email protected]>
Date: Wednesday, February 25, 2026 at 11:01
To: [email protected] <[email protected]>, Andy Goryachev 
<[email protected]>, [email protected] <[email protected]>
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" <[email protected]>
An: "Andy Goryachev" <[email protected]>, "[email protected]" 
<[email protected]>
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<https://urldefense.com/v3/__https://github.com/andy-goryachev-oracle/Test/blob/main/doc/Experiments/NodeProperties.md__;!!ACWV5N9M2RV99hQ!Ie39KHLQqoER4VeWP4KDgwa3XMIaPBzgSg5sb8HylkbYhnc-m6ZCEp47-JW4rGw_H6HC8QAiqE2XdTmaWPoLWy23$>
 , 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 
<[email protected]><mailto:[email protected]> on behalf 
of John Hendrikx <[email protected]><mailto:[email protected]>
Date: Thursday, February 19, 2026 at 15:28
To: [email protected]<mailto:[email protected]> 
<[email protected]><mailto:[email protected]>
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<https://urldefense.com/v3/__https://github.com/andy-goryachev-oracle/Test/blob/main/doc/Experiments/NodeProperties.md__;!!ACWV5N9M2RV99hQ!Ie39KHLQqoER4VeWP4KDgwa3XMIaPBzgSg5sb8HylkbYhnc-m6ZCEp47-JW4rGw_H6HC8QAiqE2XdTmaWPoLWy23$>

Reply via email to