Scene lifecycle15 / 19

Memory leaks: a reference keeps the object alive

Finishing a scene does not automatically make its event listener unreachable.

The player closed the scene, but a global event target still holds a callback that uses its data. To the developer, the scene has finished. To the garbage collector, it remains reachable.

function mount(scene) {
  const onResize = () => scene.resize();
  window.addEventListener('resize', onResize);
  return () => window.removeEventListener('resize', onResize);
}

mount(scene) returns a cleanup function. When the scene is no longer needed, that function must be called: it removes the onResize listener from window. The call to removeEventListener must receive the same handler that was originally added.

To find a leak in an application, we can compare memory snapshots after opening and closing the scene several times and check what still keeps it in memory.

Cleaning up a subscription

We will call the cleanup function and see what changes.

windowEvent handlersresize: onResize
→
onResizeEvent handler() => scene.resize()
sceneAccessible through the handler
The subscription retains the scene

window holds the onResize handler. The handler accesses scene, so the scene remains accessible through the subscription.

The diagram shows a subscription being removed. The cleanup function and other references to the scene must also be released; the engine decides when collection takes place.

Key takeaway

dispose should remove the scene's long-lived connections.

Check the primary source ↗

Chrome DevTools · Memory↗Official tools for diagnosing memory use, leaks, and frequent garbage collections.DOM Standard · removeEventListener↗The standard's rules for removing listeners: type, callback, and capture must match.