-
Notifications
You must be signed in to change notification settings - Fork 0
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 leaks in bamboo components. #66
Comments
I set up this test harness to investigate a leak in BarPlot.pointToPaintableFields, but it does not seem to leak at all. Subject: [PATCH] Use PhetioIDUtilsModule, see https://github.com/phetsims/tandem/issues/316
---
Index: js/demo/DemoBarPlot.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/demo/DemoBarPlot.ts b/js/demo/DemoBarPlot.ts
--- a/js/demo/DemoBarPlot.ts (revision c5be5907ba3f3898d478bcaa15881884b9af346a)
+++ b/js/demo/DemoBarPlot.ts (date 1734382025876)
@@ -12,7 +12,7 @@
import Vector2 from '../../../dot/js/Vector2.js';
import Orientation from '../../../phet-core/js/Orientation.js';
import MathSymbols from '../../../scenery-phet/js/MathSymbols.js';
-import { Color, Node, NodeOptions, Text, VBox } from '../../../scenery/js/imports.js';
+import { Color, ColorProperty, Node, NodeOptions, Text, VBox } from '../../../scenery/js/imports.js';
import TextPushButton from '../../../sun/js/buttons/TextPushButton.js';
import bamboo from '../bamboo.js';
import BarPlot from '../BarPlot.js';
@@ -62,6 +62,17 @@
}
} );
+ const myColorProperty = new ColorProperty( Color.blue );
+ setInterval( () => {
+ const m = new BarPlot( chartTransform, createDataSet( 2, 0.1 ), {
+ pointToPaintableFields: ( point: Vector2 ) => {
+ return { fill: myColorProperty };
+ }
+ } );
+ console.log( 'hello' );
+ m.dispose();
+ }, 100 );
+
const chartClip = new Node( {
clipArea: chartRectangle.getShape(),
children: [
Index: js/demo/BambooDemoScreenView.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/demo/BambooDemoScreenView.ts b/js/demo/BambooDemoScreenView.ts
--- a/js/demo/BambooDemoScreenView.ts (revision c5be5907ba3f3898d478bcaa15881884b9af346a)
+++ b/js/demo/BambooDemoScreenView.ts (date 1734381332066)
@@ -34,37 +34,37 @@
* {(layoutBounds: Bounds2) => Node} createNode - creates the scene graph for the demo
*/
const demos: DemoItemData[] = [
- {
- label: 'AreaPlot',
- createNode: layoutBounds => new DemoAreaPlot( { center: layoutBounds.center } )
- },
+ // {
+ // label: 'AreaPlot',
+ // createNode: layoutBounds => new DemoAreaPlot( { center: layoutBounds.center } )
+ // },
{
label: 'BarPlot',
createNode: layoutBounds => new DemoBarPlot( { center: layoutBounds.center } )
},
- {
- label: 'ChartCanvasNode',
- createNode: layoutBounds => new DemoChartCanvasNode( emitter, { center: layoutBounds.center } )
- },
- {
- label: 'LinearEquationPlot',
- createNode: layoutBounds => new DemoLinearEquationPlot( { center: layoutBounds.center } )
- },
- {
- label: 'LinePlot',
- createNode: layoutBounds => new DemoLinePlot( { center: layoutBounds.center } )
- },
- {
- label: 'MultiplePlots', createNode: layoutBounds => new DemoMultiplePlots( { center: layoutBounds.center } )
- },
- {
- label: 'ScatterPlot',
- createNode: layoutBounds => new DemoScatterPlot( { center: layoutBounds.center } )
- },
- {
- label: 'UpDownArrowPlot',
- createNode: layoutBounds => new DemoUpDownArrowPlot( { center: layoutBounds.center } )
- }
+ // {
+ // label: 'ChartCanvasNode',
+ // createNode: layoutBounds => new DemoChartCanvasNode( emitter, { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'LinearEquationPlot',
+ // createNode: layoutBounds => new DemoLinearEquationPlot( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'LinePlot',
+ // createNode: layoutBounds => new DemoLinePlot( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'MultiplePlots', createNode: layoutBounds => new DemoMultiplePlots( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'ScatterPlot',
+ // createNode: layoutBounds => new DemoScatterPlot( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'UpDownArrowPlot',
+ // createNode: layoutBounds => new DemoUpDownArrowPlot( { center: layoutBounds.center } )
+ // }
];
super( demos, {
Perhaps a Rectangle that is cut off from the GC roots also does not retain a reference for |
I'd be very surprised if that were the case. TickLabelSet was leaking due to My bad, BarPlot is not leaking, because it does not pass anything observable to Rectangle: const rectangle = new Rectangle( 0, 0, 0, 0 ); SpanNode can leak via const arrowNode = new ArrowNode(
leftBar.right,
leftBar.centerY,
rightBar.left,
rightBar.centerY,
this.arrowNodeOptions
); UpDownArrowPlot can also leak via const arrowNode = new ArrowNode( 0, 0, 0, 0, this.arrowNodeOptions ); |
Here's a propose (untested) patch for SpanNode and UpDownArrowNode. Please review, feel free to apply and commit if it looks correct. patchSubject: [PATCH] visibleProperty phetioReadOnly: true, https://github.com/phetsims/natural-selection/issues/366
---
Index: js/UpDownArrowPlot.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/UpDownArrowPlot.ts b/js/UpDownArrowPlot.ts
--- a/js/UpDownArrowPlot.ts (revision c5be5907ba3f3898d478bcaa15881884b9af346a)
+++ b/js/UpDownArrowPlot.ts (date 1734454885841)
@@ -67,7 +67,10 @@
const changedListener = () => this.update();
chartTransform.changedEmitter.addListener( changedListener );
- this.disposeUpDownArrowPLot = () => chartTransform.changedEmitter.removeListener( changedListener );
+ this.disposeUpDownArrowPLot = () => {
+ chartTransform.changedEmitter.removeListener( changedListener );
+ this.arrowNodes.forEach( node => node.dispose );
+ };
}
// Sets the dataSet and redraws the plot.
@@ -92,6 +95,7 @@
// if any data points were removed, remove any extra ArrowNodes
while ( this.arrowNodes.length > this.dataSet.length ) {
const arrowNode = this.arrowNodes.pop()!;
+ arrowNode.dispose();
this.removeChild( arrowNode );
}
Index: js/SpanNode.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/SpanNode.ts b/js/SpanNode.ts
--- a/js/SpanNode.ts (revision c5be5907ba3f3898d478bcaa15881884b9af346a)
+++ b/js/SpanNode.ts (date 1734454885835)
@@ -43,6 +43,7 @@
private readonly color: string | Color;
private readonly outerLineLength: number;
private viewWidth: number;
+ private arrowNode?: ArrowNode;
private readonly arrowNodeOptions: ArrowNodeOptions;
private readonly disposeSpanNode: () => void;
@@ -92,7 +93,10 @@
const changedListener = () => this.update();
chartTransform.changedEmitter.addListener( changedListener );
- this.disposeSpanNode = () => chartTransform.changedEmitter.removeListener( changedListener );
+ this.disposeSpanNode = () => {
+ chartTransform.changedEmitter.removeListener( changedListener );
+ this.arrowNode && this.arrowNode.dispose();
+ };
}
/**
@@ -116,11 +120,13 @@
//TODO https://github.com/phetsims/bamboo/issues/21 support Orientation.VERTICAL
+ this.arrowNode && this.arrowNode.dispose();
+
// Create double-headed arrow with perpendicular lines at ends to show modelDelta
const createBar = ( centerX: number ) => new Line( 0, 0, 0, this.outerLineLength, { stroke: this.color, centerX: centerX } );
const leftBar = createBar( 0 );
const rightBar = createBar( viewWidth );
- const arrowNode = new ArrowNode(
+ this.arrowNode = new ArrowNode(
leftBar.right,
leftBar.centerY,
rightBar.left,
@@ -128,7 +134,7 @@
this.arrowNodeOptions
);
const arrowWithBars = new Node( {
- children: [ leftBar, rightBar, arrowNode ]
+ children: [ leftBar, rightBar, this.arrowNode ]
} );
//TODO https://github.com/phetsims/bamboo/issues/21 support Orientation.VERTICAL |
This line does not look correct:
Furthermore, creating a harness to try to intentionally trigger a leak SpanNode does not cause a leak in main (without the patch above): Subject: [PATCH] Use PhetioIDUtilsModule, see https://github.com/phetsims/tandem/issues/316
---
Index: js/demo/DemoBarPlot.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/demo/DemoBarPlot.ts b/js/demo/DemoBarPlot.ts
--- a/js/demo/DemoBarPlot.ts (revision c5be5907ba3f3898d478bcaa15881884b9af346a)
+++ b/js/demo/DemoBarPlot.ts (date 1734535988283)
@@ -12,13 +12,14 @@
import Vector2 from '../../../dot/js/Vector2.js';
import Orientation from '../../../phet-core/js/Orientation.js';
import MathSymbols from '../../../scenery-phet/js/MathSymbols.js';
-import { Color, Node, NodeOptions, Text, VBox } from '../../../scenery/js/imports.js';
+import { Color, ColorProperty, Node, NodeOptions, Text, VBox } from '../../../scenery/js/imports.js';
import TextPushButton from '../../../sun/js/buttons/TextPushButton.js';
import bamboo from '../bamboo.js';
import BarPlot from '../BarPlot.js';
import ChartRectangle from '../ChartRectangle.js';
import ChartTransform from '../ChartTransform.js';
import GridLineSet from '../GridLineSet.js';
+import SpanNode from '../SpanNode.js';
import TickLabelSet from '../TickLabelSet.js';
import TickMarkSet from '../TickMarkSet.js';
@@ -62,6 +63,17 @@
}
} );
+ const myColorProperty = new ColorProperty( Color.blue );
+ setInterval( () => {
+ const s = new SpanNode( chartTransform, Orientation.HORIZONTAL, Math.PI * 12, new Text( 'hello' ), {
+ arrowNodeOptions: {
+ fill: myColorProperty // Intentional attempt to leak by attaching to the color Property above
+ }
+ } );
+ console.log( 'hello' );
+ s.dispose();
+ }, 100 );
+
const chartClip = new Node( {
clipArea: chartRectangle.getShape(),
children: [
Index: js/demo/BambooDemoScreenView.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/demo/BambooDemoScreenView.ts b/js/demo/BambooDemoScreenView.ts
--- a/js/demo/BambooDemoScreenView.ts (revision c5be5907ba3f3898d478bcaa15881884b9af346a)
+++ b/js/demo/BambooDemoScreenView.ts (date 1734535667568)
@@ -34,37 +34,37 @@
* {(layoutBounds: Bounds2) => Node} createNode - creates the scene graph for the demo
*/
const demos: DemoItemData[] = [
- {
- label: 'AreaPlot',
- createNode: layoutBounds => new DemoAreaPlot( { center: layoutBounds.center } )
- },
+ // {
+ // label: 'AreaPlot',
+ // createNode: layoutBounds => new DemoAreaPlot( { center: layoutBounds.center } )
+ // },
{
label: 'BarPlot',
createNode: layoutBounds => new DemoBarPlot( { center: layoutBounds.center } )
},
- {
- label: 'ChartCanvasNode',
- createNode: layoutBounds => new DemoChartCanvasNode( emitter, { center: layoutBounds.center } )
- },
- {
- label: 'LinearEquationPlot',
- createNode: layoutBounds => new DemoLinearEquationPlot( { center: layoutBounds.center } )
- },
- {
- label: 'LinePlot',
- createNode: layoutBounds => new DemoLinePlot( { center: layoutBounds.center } )
- },
- {
- label: 'MultiplePlots', createNode: layoutBounds => new DemoMultiplePlots( { center: layoutBounds.center } )
- },
- {
- label: 'ScatterPlot',
- createNode: layoutBounds => new DemoScatterPlot( { center: layoutBounds.center } )
- },
- {
- label: 'UpDownArrowPlot',
- createNode: layoutBounds => new DemoUpDownArrowPlot( { center: layoutBounds.center } )
- }
+ // {
+ // label: 'ChartCanvasNode',
+ // createNode: layoutBounds => new DemoChartCanvasNode( emitter, { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'LinearEquationPlot',
+ // createNode: layoutBounds => new DemoLinearEquationPlot( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'LinePlot',
+ // createNode: layoutBounds => new DemoLinePlot( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'MultiplePlots', createNode: layoutBounds => new DemoMultiplePlots( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'ScatterPlot',
+ // createNode: layoutBounds => new DemoScatterPlot( { center: layoutBounds.center } )
+ // },
+ // {
+ // label: 'UpDownArrowPlot',
+ // createNode: layoutBounds => new DemoUpDownArrowPlot( { center: layoutBounds.center } )
+ // }
];
super( demos, {
Please advise. |
Why does Why do you think that ArrowNode will not leak if it's linked to a global Property and not disposed? Let's chat on Zoom instead of assigning this back and forth. |
It is not calling the dispose() function (missing parens).
I demonstrated it empirically by running the memory profiler with my patch and observing that there was no memory leak.
I'm on zoom at the moment, or please reach out to me on slack to schedule a time. |
@pixelzoom and I met and reproduced the example above. We were both surprised that there is no leak in the patch. We would like to ask @jonathanolson how this is happening, and whether the same can be done for StringProperty instances. |
@samreid and I discussed. We suspect that scenery is automatically cleaning up links to color Properties (for fill, stroke,...) but is not cleaning up links to string Properties (Text, RichText). @samreid will confirm with @jonathanolson. If that's the case, then this issue can be closed. And it would be nice to discuss making scenery automatically cleanup string Property links (Text, RichText) since they have been a continual cost and problem while converting sims to dynamic locale. |
How can I reproduce the leak? I'd be interested to try it out and debug. |
@jonathanolson @samreid and I discussed. Scenery does not create links to color Properties (fill, stroke, ...) so the "leaks" that I identified herein are a non-issue, and this can be closed without further work. @samreid thanks for demonstrating the lack of leakage and getting us to the bottom of this. Automatically cleanup string Property links (Text, RichText) is not possible. We can't simply dispose a Text/RichText when it's removed from the scene graph because we may intended to add it again later. So Text/RichText instances (like those in #64 TickLabelSet) do need to be explicitly disposed. |
After my experience with #64, I decided to review bamboo components for other memory leaks. Here's what I found:
BarPlot: creates a set ofRectangle
instances that make be linked to global ProfileColorProperty.ArrowNode
instance that may be linked to a global ProfileColorProperty.ArrowNode
instances that may be linked to global ProfileColorProperty.These leaks need to be addressed in the
update
anddispose
methods of each component.These components are not an issue for phetsims/fourier-making-waves#123. FMW does not use SpanNode and UpDownArrowPlot. And while it uses BarPlot, a single instance is reused, and the number of bars is constant.
@samreid FYI.
The text was updated successfully, but these errors were encountered: