[Memory leak] Context is not cleared if it references a Promise
MayurRJoshi opened this issue · comments
Summary
If the context contains a key which references a Promise, then that context object is never cleared. Hence, the _contexts
map keeps growing and hogs up all the heap memory.
Steps to reproduce
- Install
express
andcls-hooked
. - Run the script below,
node --inspect index.js
const express = require('express')
const clsHooked = require('cls-hooked')
clsHooked.createNamespace('test')
const app = express()
app.get('/', (req, res, next) => {
const namespace = clsHooked.getNamespace('test')
console.log(namespace._contexts)
namespace.run(() => {
namespace.set('x', Promise.resolve())
res.json({})
})
})
app.listen(3030, () => console.log(('Listening')))
- Call the server api,
curl localhost:3030
- [Optional] Manually trigger a garbage collection from the Chrome debugger.
- Repeat 3 and 4 and observe the logs. Notice that the
_contexts
keeps growing even after a manual garbage collection
node --inspect index.js
Debugger listening on ws://127.0.0.1:9229/05303a92-c1ac-4cdb-816a-4b5e15de611a
For help, see: https://nodejs.org/en/docs/inspector
Listening
Debugger attached.
Map {}
Map {
16 => { _ns_name: 'test', id: 11, x: Promise { undefined } },
22 => { _ns_name: 'test', id: 11, x: Promise { undefined } } }
Map {
16 => { _ns_name: 'test', id: 11, x: Promise { undefined } },
39 => { _ns_name: 'test', id: 34, x: Promise { undefined } } }
Map {
16 => { _ns_name: 'test', id: 11, x: Promise { undefined } },
39 => { _ns_name: 'test', id: 34, x: Promise { undefined } },
61 => { _ns_name: 'test', id: 56, x: Promise { undefined } } }
Map {
16 => { _ns_name: 'test', id: 11, x: Promise { undefined } },
39 => { _ns_name: 'test', id: 34, x: Promise { undefined } },
61 => { _ns_name: 'test', id: 56, x: Promise { undefined } },
84 => { _ns_name: 'test', id: 79, x: Promise { undefined } },
90 => { _ns_name: 'test', id: 79, x: Promise { undefined } } }
If I change the set
to namespace.set('x', '')
(or any other primitive or object), context is cleared sometimes automatically after every request and always if a manual garbage collection is triggered.
Output with no manual GC.
node --inspect index.js
Debugger listening on ws://127.0.0.1:9229/d39a47e8-72a2-4603-885a-ba0e3dbd8d53
For help, see: https://nodejs.org/en/docs/inspector
Listening
Map {}
Map { 21 => { _ns_name: 'test', id: 11, x: '' } }
Map {}
Map {}
Map {}