Are ES Modules garbage collected? If so, do they re-execute on next import?

# #!/JoePea (14 days ago)

I am curious: can modules be garbage collected if the exports are not references by anything anymore? And if so, will the module be re-evaluated the next time it is imported?

I haven't tried an experiment to answer this yet. I'll be back to post findings if someone doesn't post an official answer first.

I'm thinking about code longevity. For example, if we make long-running web-based applications with many routes and features (for sake of example imagine a desktop environment, or a MMORPG game, with apps or components that are loaded within the same context). Over time, if imports are not collected, then it means we have a memory leak.

Imagine, for example, an infinite-universe MMORPG where you can land on different planets where the code for features of a planet are provided by third parties as ES Modules. I know, this might not be a safe idea to import any code into an app, but just imagine it for sake of example (imagine we have a continuous integration system to test and verify code security, or something, before that code is allowed to be consumed in the app). Imagine you play this app for many many days, and visit many places, and you leave the app running the whole time (because farming for resources is disabled if the app is not running, or something).

I would imagine that we want unused modules (when we leave a planet, for example) to be (destroyed) garbage collected so that we don't waste memory.

#!/JoePea

# Gus Caplan (14 days ago)

Modules in the spec are cached by specifier by modules that import them. Modules in major implementations are additionally cached for the entire realm by absolute URLs. I would say that for actual code (functions and classes and whatnot) leaks aren't really a problem. Even if you import a ton of levels, that's not that much memory. The main concern I've seen raised is JSON modules, where once you import them the JSON object, which can be quite large, will never be collected. Of course, there is a simple solution to that (fetch) so it isn't a world ending problem.

# Isiah Meadows (14 days ago)

Just to expand on that, if the module record itself is dereferenced (like if it's evicted from the cache somehow), then yes, it should be collected as appropriate. However, I'm not aware of any major implementation that offers that functionality.


Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# Andrea Giammarchi (14 days ago)

even if dereferenced, a dynamic import could re-reference it any time, and I would expect it to still be the same module, it'd be a surprise otherwise (cached things, same namespace checks, etc).

# Isiah Meadows (14 days ago)

That's part of the caching I'm referring to. And if the cache entry for it has been evicted, I would not expect it to necessarily return the same instance, consistent with the behavior with require and require.cache in Node (and similar with most other module loaders that support cache eviction).


Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# Mark S. Miller (13 days ago)

No, definitely not. The table from specifiers to module instances is indexed by specifiers. Specifiers are strings, so this table is not weak. It is not a "cache" in the sense that it is allowed to drop things. Rather it is a registry of module instances. Only a registry as a whole can be gc'ed, and which point that context is no longer around for instantiating or reinstantiating modules.

As you suggest, if it could drop things because of GC that it would then need to regenerate, that would expose the non-determinism of gc. That would be a big deal. We carefully designed WeakMaps so that gc was non-observable. WeakMaps introduce no observable non-determinism. WeakRefs alone expose the non-determinism of gc, and are kept well quarantined from the rest of the language.