On Sat, 13 Jun 2026 16:31:35 GMT, Michael Strauß <[email protected]> wrote:

>> I agree, but my thought behind was not the GC, but rather this:
>> 
>> We can change just the skin at runtime. 
>> In this case we would still have stale references to the `disclosureNode` 
>> here in the `Map`. 
>> And the `disclosureNode` can still exist after we changed the skin, as the 
>> `TableRow` is unchanged (and the `disclosureNode` comes from it). Then this 
>> skin might not be GC'ed at all.
>> 
>> Also it is allowed to re-use a skin. So e.g. we could replace the skin of 
>> `TableRow` with another one, and then back to the previous one. 
>> I don't think this will work right now because everything is done in the 
>> constructor (and not in `install()`), but that might be possible in the 
>> future.
>> 
>> I agree both are rare situation and something you most likely don't do. 
>> But since it does not hurt to clear/null the fields here, and we are 
>> improving the skin in case it is not possible to dispose (GC) it 
>> immediately, I think we should rather do it and are safe for whatever a 
>> developer might do.
>
>> I agree, but my thought behind was not the GC, but rather this:
>> 
>> We can change just the skin at runtime. In this case we would still have 
>> stale references to the `disclosureNode` here in the `Map`. And the 
>> `disclosureNode` can still exist after we changed the skin, as the 
>> `TableRow` is unchanged (and the `disclosureNode` comes from it). Then this 
>> skin might not be GC'ed at all.
> 
> The disclosure node must not strongly reference the skin after the skin is 
> removed. If it does, it's a bug that needs to be fixed, because that would 
> mean that a removed skin will stick around and not be collected. I don't 
> think there is a bug here: it's okay if the skin strongly references the 
> disclosure node; it's just the other way that would be a problem.
> 
>> Also it is allowed to re-use a skin. So e.g. we could replace the skin of 
>> `TableRow` with another one, and then back to the previous one. I don't 
>> think this will work right now because everything is done in the constructor 
>> (and not in `install()`), but that might be possible in the future.
> 
> No, it's not allowed to reuse a skin. In the `SkinBase(C)` constructor, the 
> `control` field is assigned to hold the associated control. This field is 
> nulled in `SkinBase.dispose()`, so installing the same skin again on the 
> control will fail with NPE if the `control` field is dereferenced at any 
> point.
> 
>> I agree both are rare situation and something you most likely don't do. But 
>> since it does not hurt to clear/null the fields here, and we are improving 
>> the skin in case it is not possible to dispose (GC) it immediately, I think 
>> we should rather do it and are safe for whatever a developer might do.
> 
> It _does_ hurt to null fields of a disposed object, because it suggests that 
> this would do anything meaningful (like fixing a memory leak). But that's not 
> the case: if there was a memory leak (i.e. if the skin wasn't eligible for GC 
> and therefore kept its referenced objects alive), nulling the field would 
> just hide the problem. The solution in that case would be to ensure that a 
> disposed skin is eligible for GC.

Just to make it more clear what exactly I was worried about, this situation:


treeTableRow.setDisclosureNode(node)
└── TreeTableRowSkin picks it up
    └── stores in Map<Node, FadeTransition>

treeTableRow.setSkin(new TreeTableRowSkin(treeTableRow))
└── Old Skin disposed, new TreeTableRowSkin picks it up
    └── stores in Map<Node, FadeTransition> as well

Old skin has the reference and new one has.

I did run some tests and could not find a problem. Still was a bit worried as 
it was not always clear how to correctly write the skin so it follows the best 
practices. 
I think in the past the people probably chose to rather clear/null everything 
to be safe. Or, I saw a comment somewhere IRC that this was done to 'help' the 
GC. So yeah, a bit out of place and I personally then just followed the `null 
everything` pattern as I saw it quite often.

Example in the super class of `TableRowSkinBase`:
https://github.com/openjdk/jfx/blob/2abb9a3b0a7e1071bea0b8bf2ca3d83e6fdf25f8/modules/javafx.controls/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java#L246-L252

> No, it's not allowed to reuse a skin

Yes (although this can be achieved when extending from `Skin` and using the 
`install` method correctly - too much work). Just brought it up so we think 
about everything. But does not affect us in any way.

-------------

PR Review Comment: https://git.openjdk.org/jfx/pull/2177#discussion_r3409860752

Reply via email to