7

I am experiencing with JavaScript weakmaps, after trying this code in google chrome developer console, running with --js-flags="--expose-gc", I don't understand why the weakmap keep having a reference to a.b if a is gc'ed.

var a = {listener: function(){ console.log('A') }}
a.b = {listener: function(){ console.log('B') }}

var map = new WeakMap()

map.set(a.b, [])
map.set(a, [a.b.listener])

console.log(map) // has both a and a.b

gc()
console.log(map) // still have both a and a.b

a = undefined
gc()
console.log(map) // only have a.b: why does still have a reference to a.b? Should'nt be erased?
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
  • This looks like a bug to me. Does it persist if you `gc()` multiple times? If so then you should probably report it with V8. – Bergi Jul 05 '16 at 12:49

1 Answers1

5

UPDATE 2/2020

When I run this code now, it works as expected. I think having the console open was causing objects to be held onto in previous versions of Chrome but not now. Reassigning the value of a variable that holds a reference to an object will cause that object to be garbage collected (assuming nothing else has a reference to it).


In your example code, you're not releasing your a variable. It's a top level var that never goes out of scope and never gets explicitly de-referenced, so it stays in the WeakMap. WeakMap/WeakSet releases objects once there are no more references to it in your code. In your example, if you console.log(a) after one of your gc() calls, you'd still expect a to be alive, right?

So here's a working example showing WeakSet in action and how it'll delete an entry once all references to it are gone: https://embed.plnkr.co/cDqi5lFDEbvmjl5S19Wr/

const wset = new WeakSet();

// top level static var, should show up in `console.log(wset)` after a run
let arr = [1];
wset.add(arr);

function test() {
  let obj = {a:1}; //stack var, should get GCed
  wset.add(obj);
}

test();

//if we wanted to get rid of `arr` in `wset`, we could explicitly de-reference it
//arr = null;

// when run with devtools console open, `wset` always holds onto `obj`
// when devtools are closed and then opened after, `wset` has the `arr` entry,
// but not the `obj` entry, as expected
console.log(wset);

Note that having Chrome dev tools opened prevents some objects from getting garbage collected, which makes seeing this in action more difficult than expected :)

ccnokes
  • 5,909
  • 4
  • 40
  • 49
  • "you're not releasing your a variable" I think setting the variable value to `undefined` should be enough. If it is now, can you please explain why? – Suma Feb 20 '20 at 10:26
  • @Suma when I run the OP's code now, it works as expected. I think having the console open was causing objects to be held onto in previous versions of Chrome but not now. ‍♂️ – ccnokes Feb 20 '20 at 22:25
  • Interesting to know. Still I am afraid I have to insist the leading sentence "In your example code, you're not releasing your a variable. It's a top level var that never goes out of scope" is wrong, as setting the variable to null or undefined (or any other value) should make the original value of the variable eligible for collection. – Suma Feb 21 '20 at 08:27