You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Anytime a component that has a local modifier or helper is rendered, that modifier/helper object/function will be retained in memory even after the component is un-rendered (it is released when the app exits). The fact that it is retained after the component is un-rendered is why I'm calling it a memory leak.
This has two implications that, especially when considered together, can cause quite a lot of memory to leak:
If the helper/modifier is one-per-instance, e.g. readonly myHelper = function myHelper() { return 'hello'; }, then a copy of the myHelper function will leak for each component instance that is rendered/un-rendered
If the helper/modifier closes over the component instance (e.g. an arrow function that references this), then the component instance itself will leak
🔬 Minimal Reproduction
This repository contains a minimal reproduction of the issue, both via an integration test, and steps for a manual repro in the dummy app.
😕 Actual Behavior
After rendering and un-rendering a component that invokes a local helper, that local helper function leaks.
🤔 Expected Behavior
It should be released when the component is un-rendered.
🌍 Environment
Ember: 5.2.0
Node.js/npm: 16.15.1
OS: MacOS
Browser: Chrome/Firefox/Safari
➕ Additional Context
I dug in some and believe I have a diagnosis of the problem. Here is the culprit retainer chain:
The CompileTimeCompilationContextImpl is effectively a singleton, as is ConstantsImpl. When the local helper is first invoked, ConstantsImpl's helper() method is invoked, which calls into value(), which puts an object containing the helper arrow function in a this.values and this.indexMap:
They are not removed until the app exits.
This is some guesswork, but it appears that these helpers are being stored in the same place as global helpers, so the pattern is to keep them cached forever, but really they should be stored in a place/manner such that their lifetime is bound to the lifetime of the component, and/or they should stored via weak references.
The text was updated successfully, but these errors were encountered:
🐞 Describe the Bug
Anytime a component that has a local modifier or helper is rendered, that modifier/helper object/function will be retained in memory even after the component is un-rendered (it is released when the app exits). The fact that it is retained after the component is un-rendered is why I'm calling it a memory leak.
This has two implications that, especially when considered together, can cause quite a lot of memory to leak:
readonly myHelper = function myHelper() { return 'hello'; }
, then a copy of themyHelper
function will leak for each component instance that is rendered/un-renderedthis
), then the component instance itself will leak🔬 Minimal Reproduction
This repository contains a minimal reproduction of the issue, both via an integration test, and steps for a manual repro in the dummy app.
😕 Actual Behavior
After rendering and un-rendering a component that invokes a local helper, that local helper function leaks.
🤔 Expected Behavior
It should be released when the component is un-rendered.
🌍 Environment
➕ Additional Context
I dug in some and believe I have a diagnosis of the problem. Here is the culprit retainer chain:
The
CompileTimeCompilationContextImpl
is effectively a singleton, as isConstantsImpl
. When the local helper is first invoked,ConstantsImpl
'shelper()
method is invoked, which calls intovalue()
, which puts an object containing the helper arrow function in athis.values
andthis.indexMap
:They are not removed until the app exits.
This is some guesswork, but it appears that these helpers are being stored in the same place as global helpers, so the pattern is to keep them cached forever, but really they should be stored in a place/manner such that their lifetime is bound to the lifetime of the component, and/or they should stored via weak references.
The text was updated successfully, but these errors were encountered: