I'm updating an opensource project of mine, an object-changes notifier that uses RxJS. To achieve this, I'm using a Weakmap to keep tracking of object position and "property chain" (e.g. "a.b.c", ...). I'm setting as Weakmap keys ES6 Proxies, all with the same handlers.
I've created a wrapper class that, in its constructor iterates the source-object and returns a "Proxy-chain" (i.e. if a property is an object, it becomes a Proxy, and so on). To iterate the objects, it uses the function below.
The problem I'm experiencing seems to be a memory-leak (I suppose) that I'm not able to understand where it comes from. The problem happens also without using the class, so I think that might be related to this function somehow.
function createProxyChain(sourceObject, handlers, all, parents) {
const descriptors = Object.getOwnPropertyDescriptors(sourceObject);
const targetObjectKeys = Object.keys(descriptors);
for (let i = targetObjectKeys.length, prop; prop = targetObjectKeys[--i];) {
if (sourceObject[prop] && typeof sourceObject[prop] === "object") {
const parentChains = parents && parents.map(c => `${c}.${prop}`) || [prop];
const proxyChain = createProxyChain(sourceObject[prop], handlers, all, parentChains);
descriptors[prop].value = proxyChain;
all.set(proxyChain, null);
}
}
const chain = Object.create(Object.getPrototypeOf(sourceObject) || {}, descriptors);
const proxiedChain = new Proxy(chain, handlers);
return proxiedChain;
}
And to execute it:
var wk = new WeakMap();
var myObject = {
a: 1,
b: {
c: 2,
d: {
e: 3,
f: {
g: 4,
h: {
i: 5,
j: {
k: 6,
l: {
m: 7,
n: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
}
}
}
}
}
}
}
createProxyChain(myObject, {}, wk);
Once the function ends, I'm getting my WeakMap with about 10 keys. If I force Garbage Collector run in Chrome/Node through flags and (window|global).gc([true])
, I expect them to be removed, shouldn't they?
Instead, the Weakmap remains filled and I can see it by logging the Weakmap in the console. In a big test I created with a lot of setting actions it might reach over 100 keys. Is this behavior correct, or there's actually a memory-leak?
It seems to happen even if I save not-proxy elements in the object instead of proxy ones. It happens also if I do myObject = null
(to remove any possible reference).
Thank you very much.