const fs = require('fs');
const ah = require('async_hooks');
let hook = ah.createHook({
init,
destroy
});
hook.enable();
hook = null;
function init(asyncId) {
fs.writeSync(1, `init ${asyncId}\n`);
}
function destroy(asyncId) {
fs.writeSync(1, `destroy ${asyncId}\n`);
}
function run(cb) {
return Promise.resolve(1)
.then(() => {
return cb();
});
}
run(cb);
function cb() {
setTimeout(onTimeout, 300);
}
function onTimeout() {
console.log('onTimeout');
}
Output:
init 5
init 6
init 7
init 8
onTimeout
init 9
destroy 7
destroy 9
destroy 8
Expected output:
init 5
init 6
init 7
init 8
onTimeout
init 9
destroy 7
destroy 9
destroy 8
destroy 6
destroy 5
This is mostly the same as #32939.
If you add global.gc() in onTimeout the Promise is collected and destroy is emitted.
Triggering gc in the sync flow wont work here as the Promises are async and there are still references to it after the sync part is finished.
Promises are quite lightweight objects therefore quite a lot of them may be in memory until they get collected.
Closing as answered.
Most helpful comment
This is mostly the same as #32939.
If you add
global.gc()inonTimeoutthe Promise is collected and destroy is emitted.Triggering gc in the sync flow wont work here as the Promises are async and there are still references to it after the sync part is finished.
Promises are quite lightweight objects therefore quite a lot of them may be in memory until they get collected.