0

There is another question that asks the same, but I cannot grok the accepted answer.

The library in question appears to use Object.defineProperty to add a reference to the object to be stored (albeit indirectly via another object).

But... surely that would then mean the object cannot be garbage collected because of this link?

What am I missing?

Is it really possible to create an object and store it somewhere without maintaining a reference noticeable by the garbage collector? (Prior to ES2015)

The accepted answer:

It took me a while to grok the code, but then it hit me: the key itself is used to store a reference to the value.

For example, several layers into set it does

defProp(obj, globalID, { value: store }); where defProp has been defined to be Object.defineProperty, obj is the key, globalID is a guid and store is a storage object that contains the value.

Then down in get it looks up the value with

obj[globalID];

This is very clever. The WeakMap doesn't actually contain a reference to anything (weak or otherwise)-- it just sets up a policy of where to secretly store the value. The use of Object.defineProperty means that you won't accidentally discover the value storage-- you have to know the magic guid to look it up.

Since the key directly refers to the value (and the WeakMap doesn't refer to it), when all references to the key are gone, it gets GCed like normal.

The library in question.

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • Of course the key references the value, otherwise you couldn't look it up. The value is not garbage collected until the key is. The point of a weak map is that there's no reference from the *map object* to either key or value. – Bergi Jun 06 '17 at 12:22

2 Answers2

1

surely that would then mean the object cannot be garbage collected because of this link?

Yes.

What am I missing?

Nothing. Maybe that this is exactly the desired behaviour.

As the answer explains, "the WeakMap doesn't actually contain a reference to anything (weak or otherwise)" and "when all references to the key are gone, it gets GCed like normal."

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • ...but whatever data structure used to store the value maintains a link. And if the object is never GC'd then that isn't very "weak"? – Ben Aston Jun 06 '17 at 12:35
  • I'm not sure what you expected there. It's not weak references that allow observing GC. The "weak" in `WeakMap` is only about the link from the map to the keys and values. – Bergi Jun 06 '17 at 15:58
  • In an ES2015 WeakMap I can add an object to it, nullify all other references to that object, and said object will be eligible for GC. In this library I can add an object to its "weakmap" and nullify all references to the object and it will not be GC'd until I dig into the data structure used by the library to store the object, and nullify the reference there. Thereby negating the point of the library. I am certain I am missing something. – Ben Aston Jun 06 '17 at 16:01
  • 1
    @BenAston Yes, it looks like you have not understood the library design completely. "*The key directly refers to the value, and the WeakMap doesn't refer to it*". There is no "data structure used by the library" inside the map. – Bergi Jun 06 '17 at 16:10
0

The code in the library in question is convoluted. But based on another, clearer, WeakMap implementation I have the following...

A WeakMap holds a weak reference to both the key and the value associated with it. This means the WeakMap does not affect in any way the garbage collection of with the key object or the value object.

On way to achieve this in ES5 is to add a (hidden if you want) property to the key used when it is "added" to the map and then do nothing else (ie do not add the key to an array or indeed do anything with it). In that way nothing refers to the key other than itself.

AFAICT WeakMap has a limited API for this reason. You cannot, for example, enumerate the items in a WeakMap because it holds no references to its contents!

Note that the key in a WeakMap cannot be a primitive (string, number, undefined, null, Symbol, boolean).

When using has or get, you can simply look for the secret property on the object supplied as the key.

If it is present, the WeakMap "contains" or "has" it; otherwise it doesn't.

For get, the secret property could contain a reference to the value associated with the key object, again, with no reference from WeakMap to the key object or the value object.

I think.

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • The WeakMap also doesn't strongly reference the value. The reference to the whole key-value-pair is weak. – Bergi Jun 07 '17 at 08:02