Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak in Carousel? #841

Closed
zepumph opened this issue Apr 10, 2023 · 8 comments
Closed

Memory leak in Carousel? #841

zepumph opened this issue Apr 10, 2023 · 8 comments

Comments

@zepumph
Copy link
Member

zepumph commented Apr 10, 2023

Over in #797, I see that Carousel.carouselItemNodes is created with getGroupItemNodes, but not disposed. I am confident enough that this is a leak that I'll commit and then assign to review.

zepumph added a commit that referenced this issue Apr 10, 2023
@zepumph
Copy link
Member Author

zepumph commented Apr 10, 2023

@samreid, does this seem right to you? I'm checking other usages of getGroupItemNodes in that other issue, so just a spot check should be good here.

zepumph added a commit that referenced this issue Apr 10, 2023
@zepumph
Copy link
Member Author

zepumph commented Apr 10, 2023

Ahh shoot, looks like it is done through the AlignBox, I reverted this commit.

This seems really confusing to me, could we instead dispose the alignboxes and then dispose the nodes as two different calls?

alignBox.children.forEach( child => child.dispose() );

@samreid
Copy link
Member

samreid commented Apr 10, 2023

I am confident enough that this is a leak that I'll commit and then assign to review.

From this thread and other comments like phetsims/scenery-phet#769 (comment), I'm not sure the team has a shared consensus about what constitutes a memory leak. Neglecting to dispose a component does not in itself imply a memory leak. There must also be a path from one of the heap roots.

I'm also seeing

      this.alignBoxes.forEach( alignBox => {
        alignBox.children.forEach( child => child.dispose() );
        alignBox.dispose();
      } );

Which was added in:

e2074a5

@samreid samreid assigned zepumph and unassigned samreid Apr 10, 2023
@zepumph
Copy link
Member Author

zepumph commented Apr 10, 2023

Right, that makes sense, but in common code, you don't know if a dependency injected node-creator will create a node that is a memory leak or not, so we need to have an abundance of caution (generally).

Will you please respond to #841 (comment)?

@zepumph zepumph assigned samreid and unassigned zepumph Apr 10, 2023
@samreid
Copy link
Member

samreid commented Apr 10, 2023

Right, that makes sense, but in common code, you don't know if a dependency injected node-creator will create a node that is a memory leak or not, so we need to have an abundance of caution (generally).

I agree, and in this case clients can get access to the AlignBox instances via getVisibleAlignBoxes, clients may add listeners that need cleanup.

Will you please respond to #841 (comment)?

I feel confused since that comment said: "This seems really confusing to me, could we instead dispose the alignboxes and then dispose the nodes as two different calls?" and showed alignBox.children.forEach( child => child.dispose() ); And I already replied that alignBox instances are being disposed in a separate call, and I showed the commit where that was introduced. So I feel I'm misunderstanding something.

@samreid samreid assigned zepumph and unassigned samreid Apr 10, 2023
zepumph added a commit that referenced this issue Apr 10, 2023
@zepumph
Copy link
Member Author

zepumph commented Apr 10, 2023

Do you think the code would look better like this?
Do you think we need an assertion that the AlignBox only has one child, and that it is one of our Nodes from createNode?

Subject: [PATCH] use new bad-text to keep joist global out of common code (unprotected), https://github.com/phetsims/chipper/issues/1004
---
Index: js/Carousel.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/Carousel.ts b/js/Carousel.ts
--- a/js/Carousel.ts	(revision ae7f27c20ca3f465dbf58a5ed32779ed2da2d439)
+++ b/js/Carousel.ts	(date 1681152240732)
@@ -403,11 +403,13 @@
       this.visibleAlignBoxesProperty.dispose();
       this.pageNumberProperty.dispose();
       this.alignBoxes.forEach( alignBox => {
-        alignBox.children.forEach( child => child.dispose() );
+        assert && assert( alignBox.children.length === 1, 'just one child please' );
+        assert && assert( this.carouselItemNodes.includes( alignBox.children[ 0 ] ), 'alignBox should wrap a content node' );
         alignBox.dispose();
       } );
       this.scrollingNode.dispose();
       this.carouselConstraint.dispose();
+      this.carouselItemNodes.forEach( node => node.dispose() );
     };
 
     this.mutate( options );
@@ -604,7 +606,6 @@
       const lastBox = visibleAlignBoxes[ this.itemsPerPage - 1 ] || visibleAlignBoxes[ visibleAlignBoxes.length - 1 ];
 
       const horizontalSize = new Dimension2(
-
         // Measure from the beginning of the first item to the end of the last item on the 1st page
         lastBox[ orientation.maxSide ] - visibleAlignBoxes[ 0 ][ orientation.minSide ] + ( 2 * this.margin ),
 

@samreid
Copy link
Member

samreid commented Apr 11, 2023

Looks good, thanks! I also tested by disposing a carousel and seeing that nothing unexpected happened. Anything else for this issue @zepumph ?

@samreid samreid assigned zepumph and unassigned samreid Apr 11, 2023
@zepumph
Copy link
Member Author

zepumph commented Apr 11, 2023

Thanks! I like it.

@zepumph zepumph closed this as completed Apr 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants