Open tjcrowder opened 4 years ago
I'd expect that each engine will have certain cases where objects are not live but, nevertheless, a finalizer is significantly delayed or never runs at all. So I don't think it's possible to specify anything more than we have.
At the same time, it could be good to document shared guidelines/intention here. I believe everyone intends that some things will sometimes be called, at least.
I'm not sure if anyone will take up that work item, and I don't think it blocks Stage 4. I'd put this at a lower priority than good reference documentation #170 .
@kmiller68 can clarify the JSC status. I believe there's an implementation in progress, but I'm not sure if there's a tracking issue or anything.
@littledan - Thanks. What would that documentation say, though? A) That you do need to handle never getting finalizer calls (my more complicated version of makeWeakCache
here for instance, but with deref() === undefined
instead of isReclaimed()
), or B) that while implementations are allowed to not make the calls, it's likely to be in edge cases where it's okay to just leak memory (for things like that cache), or cases where it's irrelevant (process shutdown)? Or something else? :-)
I'm not sure what this document would say exactly. I haven't been able to find similar documents for other languages. It'll be a lot of work to figure out exactly what it'd be OK to say here, I think.
TL;DR: Other than with certain caveats (see below), can developers rely on receiving finalizer calls or not? (For instance, to clean up other things related to reclaimed objects, like cache entries, WeakRefs, wasm objects...) I'm confused because some aspects of the explainer seem to suggest they can, but others (and the proposed spec text) suggest they can't. Does this need firming up and/or clarification?
Details:
I get that finalizer calls have these caveats at a minimum:
FinalizationRegistry
the objects were in is, itself, unreachable.Other than that, though, can developers reasonably rely on getting finalizer calls for cleanup purposes?
Evidence suggesting "yes, they can:"
The explainer says (my emphasis):
(Granted, "a way" doesn't necessarily mean they can always avoid it. You could read that as "a way to avoid that repeated scanning if you've ever seen a finalizer call, but you still have to have the code for repeated scanning in case you never see a finalizer call.")
The "Fixed version that doesn't leak memory" of the explainer's
makeWeakCached
example relies on finalizers to avoid leaking memory.Evidence suggesting "no, they can't:"
next
method of the finalization cleanup interator says an implementation "may" return a result object containing the held value of a cell with an empty [[WeakRefTarget]], not that it will.cleanupSome
, it won't do anything if the implementation has never set [[WeakRegTarget]]s empty.If the intention is that finalizers should be called "at some point in the future" by implementations that do perform garbage collection except in some limited situations, should the requirement be firmer/clearer? Or is it something developers can't reasonably rely on?
Thanks!
I'm curious about the intention re specified behavior/requirements. I do see that the signals are good that implementers of major engines will call finalizers; V8 and SpiderMonkey both do (behind flags at present). (I can't find any public signals for finalizers from Apple — for instance, here or here — but I haven't trawled the notes, and if V8 and SpiderMonkey both support them, it's hard to see JavaScriptCore not.)