Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Editorial: Document "independent lifetime" of FinalizationGroups #184

Merged
merged 1 commit into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ _Finalization_ is the execution of code to clean up after an object that has bec

Finalizers are tricky business and it is best to avoid them. They can be invoked at unexpected times, or not at all---for example, they are not invoked when closing a browser tab or on process exit. They don’t help the garbage collector do its job; rather, they are a hindrance. Furthermore, they perturb the garbage collector’s internal accounting. The GC decides to scan the heap when it thinks that it is necessary, after some amount of allocation. Finalizable objects almost always represent an amount of allocation that is invisible to the garbage collector. The effect can be that the actual resource usage of a system with finalizable objects is higher than what the GC thinks it should be.

The proposed specification allows conforming implementations to skip calling finalization callbacks for any reason or no reason. Some reasons why many JS environments and implementations may omit finalization callbacks:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth explicitly mentioning that if the only remaining tasks an implementation has are finalization callbacks, it can probably consider that as the time to exit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was that the first bullet point would cover this, but maybe it's too unclear. If you have a suggestion for another wording of the paragraph, or wording for an additional bullet point, that's more clear, I'd appreciate that. I'm not sure if we have a clear cross-environment meaning for "time to exit", so any wording would probably be best if it can somehow acknowledge that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@littledan I think a lot of people have this idea of JS's loop where you throw a bunch of items in and JS keeps chugging along until you either explicitly stop it (what you mention in bullet two), or it runs out of items to process. Your PR to 262 and this proposal make handling the loop a lot more abstract, but I think it is still worth explicitly mentioning because it's kind of a shift in the semantics of how you'd implement it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, suggest some wording here. My intention has been to speak specifically to that, and I'm still having trouble understanding what the following paragraph is missing (since it specifically talks about callbacks not being called on shutdown).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"If the only remaining tasks are finalization tasks, the implementation should consider the queue empty, otherwise it may be forced into an infinite loop of finalization"

Copy link
Member

@mhofman mhofman Feb 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, an implementation could do something like: "has the program consumed at least one element from the iterator? Then I may give it another chance to consume more. Else, thank you and goodbye".
Not saying implementations should do this, but they could.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mhofman the case here is that the implementation isn't planning to exit, it's just running to the completion of the queue. Like if you make a node script that creates a file, you don't have to explicitly do process.exit() at the end, it just exits when there's nothing left in the queue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "the queue" refer to even? (We're not requiring engines to have a "job queue", just to schedule the finalization at some point maybe.) I don't understand how this statement should be read by JS developers, who will be the vast majority of people who read this document. The infinite loop of finalization sounds like it makes sense in the context of your JS implementation, but I don't think it makes sense across environments, or without context, so I don't really think it makes sense to refer to it that way in this document.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@littledan "the queue" being the abstract place the implementation keeps track of "scheduled" finalization callbacks. I assume this doesn't affect other engines because they already do what I'm suggesting mentioning here, which is why I think it should be mentioned.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think I'll omit this paragraph; it just seems like a more confusing version of what I have written below. From a user perspective, the callbacks are skipped on the way out; to implement that, yes, you exit before exhausing the queue, but this is really the same thing.

- If the program shuts down (e.g., process exit, closing a tab, navigating away from a page), finalization callbacks typically don't run on the way out. (Discussion: [#125](https://github.com/tc39/proposal-weakrefs/issues/125))
- If the FinalizationGroup becomes "dead" (basically, unreachable), then finalization callbacks registered against it might not run. (Discussion: [#66](https://github.com/tc39/proposal-weakrefs/issues/66))

All that said, sometimes finalizers are the right answer to a problem. The following examples show a few important problems that would be difficult to solve without finalizers.

### Locating and responding to external resource leaks
Expand Down
3 changes: 3 additions & 0 deletions spec/abstract-jobs.html
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ <h1>Execution</h1>
<p>
Because calling HostCleanupFinalizationGroup is optional, registered objects
in a FinalizationGroup do not necessarily hold that FinalizationGroup live.
Implementations may omit FinalizationGroup callbacks for any reason,
e.g., if the FinalizationGroup itself becomes dead, or if the application
is shutting down.
</p>
</emu-note>
</emu-clause>
Expand Down