RFR: 6507038: Memory Leak in JTree / BasicTreeUI [v3]

Karl T duke at openjdk.org
Thu Jan 25 19:23:28 UTC 2024


On Wed, 24 Jan 2024 05:35:42 GMT, Prasanta Sadhukhan <psadhukhan at openjdk.org> wrote:

>> When using a TreeCellRenterer which creates new components in getTreeCellRendererComponent() in a JTree that is not visible, changes to the nodes cause a memory leak.
>> When a node is changed, the Method getNodeDimensions() is called to calculate the new dimensions for the node. In this method, getTreeCellRendererComponent() is called to obtain the renderer component (what else...) and [this component is added to rendererPane](https://github.com/openjdk/jdk/blob/36f4b34f1953af736706ec67192204727808bc6c/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java#L3283-L3284). It is not removed from the rendererPane afterwards. 
>> Only when the tree is painted, the paint() method does a removeAll on the rendererPane [in this code](https://github.com/openjdk/jdk/blob/36f4b34f1953af736706ec67192204727808bc6c/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java#L1500)
>> 
>> FIx is added to remove the components from rendererPane when the JTree UI is changed/uninstalled only when tree is not visible since they are already removed when tree is painted in paint() method..
>
> Prasanta Sadhukhan has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Retain last component in rendererPane. Testcase added

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java line 3285:

> 3283:                     for (int i = 0; i < rendererPane.getComponentCount(); i++) {
> 3284:                         rendererPane.remove(i);
> 3285:                     }

~~~java
for (int i = 0; i < rendererPane.getComponentCount(); i++) {
   rendererPane.remove(i);
}
~~~

This code will not work for two or more children!

For two children It does:
1. `i = 0`
2. `remove(i)` removes first child, which shifts other children and decrements component count to `1`!
3. `i++` so `i` is now `1`
4. check `i < rendererPane.getComponentCount()`, which is `1 < 1`. So loop is quit and one child is not removed.

For three children It does:
1. `i = 0`
2. `remove(i)` removes first child, which shifts other children and decrements component count to `2`!
3. `i++` so `i` is now `1`
4. check `i < rendererPane.getComponentCount()`, which is `1 < 2`
5. `remove(i)` removes second child, which was the third child initially and decrements component count to `1`
6. `i++` so `i` is now `2`
7. check `i < rendererPane.getComponentCount()`, which is `2 < 1` . So loop is quit and one child is not removed.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/17458#discussion_r1466820969


More information about the client-libs-dev mailing list