node-api: run finalizers directly from GC
The issue
Currently Reference
finalizers are run inside of SetImmediate
.
In case if user code creates a lot of native objects in the main script, it could cause a significant memory pressure, even if the objects are properly released. This is because they are "collected" only inside of SetImmediate
that follows the script run.
See the issue: https://github.com/nodejs/node-addon-api/issues/1140
In the https://github.com/nodejs/node/commit/a74a6e3ba131752225a527d915593d7e413b1594 commit the processing of finalizers was moved from the GC second pass to the SetImmediate
because:
- finalizers may run some arbitrary JS code while some other JS code being executed.
- finalizers may throw JavaScript exceptions which can affect behavior of other functions.
The solution
In this PR we are introducing new experimental behavior where the finalizers are run directly from the GC but they are not allowed to run JS code and must only call native code. Since the finalizers cannot affect the running JS code in any way, they are safe to run at any point.
- When the finalizers run from GC, we disable running JS code and any Node-API that may run JS code.
- Any unhandled Node-API error or JS exception will cause the process abort.
If a finalizer must run JS code, then it can do it by calling the new node_api_post_finalizer
method which schedules the finalizer run in SetImmediate
as it was before. The main difference is that previously we always scheduled finalizer runs in SetImmediate
implicitly, and now code must do it explicitly.