Skip to content

Conversation

@arapte
Copy link
Member

@arapte arapte commented Oct 13, 2020

TabPaneSkin installs some listeners that are not removed when TabPaneSkin is changed.
The fix converts listeners to WeakListeners and also removes them on dispose.

There is a NPE check change needed in isHosrizontal(). Without this check it causes NPE if pulse is in progress while TabPaneSkin is getting disposed.

SkinMemoryLeakTest already had a test which only needed to be enabled.
Test fails before and passes after this change.


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

  • JDK-8242621: TabPane: Memory leak when switching skin

Reviewers

Download

$ git fetch https://git.openjdk.java.net/jfx pull/318/head:pull/318
$ git checkout pull/318

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 13, 2020

👋 Welcome back arapte! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk openjdk bot added the rfr Ready for review label Oct 13, 2020
@mlbridge
Copy link

mlbridge bot commented Oct 13, 2020

Webrevs

@kleopatra
Copy link
Collaborator

no review yet, just a couple of quick comments from my experience on recent cleanup of skins:

  • if NPE checks seem to be necessary, they always indicate an illegal state: whatever a method is doing, it must not access the skin after dispose. Usually it's the caller of the method that's misbehaving, it simply must not happen. It's worth digging why exactly that's happening and if/how it can be solved without guarding against the null
  • while the overall memory test is already done, we still must test every single skin against side-effects (f.i. of listeners not doing any "late" update due to not being yet removed - the NPE above could well be such a case). Have a look at SkinCleanupTest for examples
  • when changing listener wiring, it's often a good idea to test that they are still doing there job (if not yet covered in the available tests)

yeah, you don't get away with not writing tests *good-humored-grinning

@kevinrushforth
Copy link
Member

/reviewers 2

@openjdk
Copy link

openjdk bot commented Oct 14, 2020

@kevinrushforth
The number of required reviews for this PR is now set to 2 (with at least 1 of role reviewers).


getSkinnable().getTabs().removeListener(weakTabsListener);

getChildren().remove(tabHeaderArea);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned offline, can you check whether removing tabHeaderArea is necessary?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good question :) Just have run into a similar case while working on cleaning up TextFieldSkin.

My current understanding is ... depends ;)

As tests show, some children keep the skin alive, others don't. Which must imply that the first somehow keep a strong reference to the skin, the latter (nor any of its children) don't. An example for the former is tabHeaderArea, an example for the latter is tabContentRegion. Was puzzled about how to distinguish the one from the other (which boils down to finding that strong reference) - until I (faintly ;) remembered that inner classes have an implicit reference to the enclosing instance: TabHeaderArea is an inner class with an implicit reference to the enclosing skin, while TabContentRegion is static nested. As long as the former reside in the scenegraph, it makes the skin leaky.

So we have to watch out for

  • explicit strong references from any node (down the hierarchy) to the skin
  • implicit strong reference to the enclosing skin class.

Both groups have to be removed in dispose to prevent memory leaks.

Even if not obviously leaking, children pile up when switching skin: most skins add to children, rarely set. We started a discussion of how to handle those that add Spinner misbehavior - not yet decided (personally, I didn't do anything about them in the cleanups, deferred to later ;) From today's knowledge, I would suggest to explicitly remove all direct children that the skin added to the control.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned offline, can you check whether removing tabHeaderArea is necessary?

Both groups have to be removed in dispose to prevent memory leaks.

The list returned by SkinBase.getChildren() is actually the same list as Parent.getChildren().
SkinBase() constructor gets the reference of Parent.getChildren() and store it's reference in the class member named children. [see here]
So, Skin and Parent share the same list of children. So when a skin is being dispose()ed, it should remove any children that it added to the list. Otherwise, those children continue to be part of scenegraph.
Please check the newly added test SkinCleanupTest.testChildrenCountAfterSkinIsReplaced().

This does not stop a skin object from getting GCed, but the Children that skin adds don't get removed from Scenegraph. Looking at this behavior, it seems like this should be done for cleanup of all Skins.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick nit-pick:

This does not stop a skin object from getting GCed,

actually, it does ... if it keeps a strong reference to the skin :)

@kleopatra
Copy link
Collaborator

quick question: is this still in the lane for fx16?

@arapte
Copy link
Member Author

arapte commented Dec 15, 2020

quick question: is this still in the lane for fx16?

Yes, I will update PR later this week.

@kleopatra
Copy link
Collaborator

quick question: is this still in the lane for fx16?

Yes, I will update PR later this week.

cool, looking forward to it :)

@kevinrushforth kevinrushforth self-requested a review December 23, 2020 00:25
@kleopatra
Copy link
Collaborator

I'm still in holiday mood - and hope you are all well :) - will review later today, have to update my notes to the latest changes.

Copy link
Collaborator

@kleopatra kleopatra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix looks good, verified tests failing (except one, commented) before and passing after the fix.

Left a couple of comments inline. Plus there's an @ignore related to the issue in TabPaneTest (testNPEOnSwitchSkinAndChangeSelection) that should be removed.

@arapte
Copy link
Member Author

arapte commented Jan 6, 2021

Fix looks good, verified tests failing (except one, commented) before and passing after the fix.

Thanks for the review. I have updated the PR according to all comments. Please take a look. :)

Copy link
Collaborator

@kleopatra kleopatra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks fine now :)

Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

@openjdk
Copy link

openjdk bot commented Jan 6, 2021

@arapte This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8242621: TabPane: Memory leak when switching skin

Reviewed-by: fastegal, kcr

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 1 new commit pushed to the master branch:

  • e74f679: 8254101: Update copyright header for files modified in 2020

Please see this link for an up-to-date comparison between the source branch of this pull request and the master branch.
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Ready to be integrated label Jan 6, 2021
@arapte
Copy link
Member Author

arapte commented Jan 7, 2021

/integrate

@openjdk openjdk bot closed this Jan 7, 2021
@openjdk openjdk bot added integrated Pull request has been integrated and removed ready Ready to be integrated rfr Ready for review labels Jan 7, 2021
@openjdk
Copy link

openjdk bot commented Jan 7, 2021

@arapte Since your change was applied there has been 1 commit pushed to the master branch:

  • e74f679: 8254101: Update copyright header for files modified in 2020

Your commit was automatically rebased without conflicts.

Pushed as commit c197b62.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@arapte arapte deleted the TabPaneSkinLeak branch May 10, 2022 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integrated Pull request has been integrated

Development

Successfully merging this pull request may close these issues.

3 participants