Nathan
Nathan

Reputation: 78439

Memory leak in React when using HTML5 Canvas

I have a project in my React app that draws to the canvas.

I'm invoking it in my component like:

function CanvasProject() {

const canvasRef = useRef(null);
const cleanup = useRef(null);

useEffect(() => {
        
        var c = canvasRef.current;
        const cleanup.current = render(c);
}, [])

return(
   <canvas style={{width: "100%"}} ref={canvasRef}>    
       Your browser does not support the HTML5 canvas tag. Stop using Netscape.
   </canvas>
)
}

The render function gets the "2d" context from the canvas a few times, gets image data with ctx.createImageData, and sets image data with ctx.putImageData.

render() also adds an onclick handler to the canvas, but I've tried commenting out that code and the memory leak is still present.

As for the memory leak itself, when I go back and forth between routes on my App, it starts to slow down the page. I'm going back and forth between routes that respectively do and do not have my component.

I've tried examining the memory usage with Firefox dev tools, and here's the memory profile when I first start the app: enter image description here

Followed by the memory usage after I go back and forth between a few routes: enter image description here

Obviously without seeing the full code I'm not expecting a "your bug is here" answer, but are there any things I should consider about the way canvas memory management works? Are there any other dev tools I could use to find out the source of the large chunks of Array and ArrayBuffer data that is being generated? Basically looking for any leads and a sanity check, to make sure I'm not missing something obvious.

Upvotes: 1

Views: 1108

Answers (1)

leavemydogalone
leavemydogalone

Reputation: 36

Can't be positive as I do not have a lot of experience with canvas, however, if the render method creates listeners then they will likely persist after the component has unmounted.

Within the useEffect hook you could try adding a function to cleanup when the component dismounts. The most likely option I could think of is change the cleanup.current to null.

useEffect(() => {   
  var c = canvasRef.current;
  const cleanup.current = render(c);

  return () => {
  cleanup.current = null;
  }

}, [])

Upvotes: 2

Related Questions