4

It is my understanding of WeakMap that "References to objects in the collection are held weakly. If there is no other reference to an object stored in the WeakMap, they can be garbage collected."

Why do the following key/value pairs still appear in the WeakMap after the references have been removed? Shouldn't the WeakMap be empty?

let dog1 = {name: 'Snickers'};
let dog2 = {name: 'Sunny'};

var strong = new Map();
var weak = new WeakMap();


strong.set(dog1, 'Snickers is the best!');
strong.set(dog2, 'Sunny is the 2nd best!');
weak.set(dog1, 'Snickers is the best!');
weak.set(dog2, 'Sunny is the 2nd best!');

dog1 = null;
dog2 = null;

console.log(strong);
console.log(weak);

/*
Output
Map(2) {{…} => "Snickers is the best!", {…} => "Sunny is the 2nd best!"}
WeakMap {{…} => "Snickers is the best!", {…} => "Sunny is the 2nd best!"}
*/

setTimeout(function(){
console.log("1200ms later... waiting for garbarge collection");
console.log(strong);
console.log(weak);
}, 1200);

/*
Output
Map(2) {{…} => "Snickers is the best!", {…} => "Sunny is the 2nd best!"}
WeakMap {{…} => "Snickers is the best!", {…} => "Sunny is the 2nd best!"}
*/
7
  • 4
    You still have a reference in strong, so they can't be garbage-collected. Commented Feb 6, 2020 at 3:17
  • "How to observe…" - you can't. Garbage collection is not guaranteed to run, even after you fix your bug. Commented Feb 6, 2020 at 3:22
  • @Bergi There's no guarantee, but the above seems fairly consistent at exhibiting the garbage collection behavior once the bug is fixed. It's fine for learning purposes (which seems to be what this question is about) as long as one doesn't rely on it to work in production code. Commented Feb 6, 2020 at 3:32
  • @JLRishe Does it now? They must have changed that, it wasn't observable in console.log'd WeakMap objects before. Commented Feb 6, 2020 at 12:21
  • @Bergi If I delete the second strong.set line and run the code in Chrome's console, the WeakMap is shown as containing dog2 prior to the setTimeout and not containing it after the timeout. The question you linked to doesn't use a timeout, so the code in that question is probably logging the weakmap before it can be garbage collected. Commented Feb 6, 2020 at 12:35

3 Answers 3

2

After fixing the bugs pointed out by @Amadan @Bergi @Geeganage, the following code gives the desired output in Safari and Chrome, with garbage collection running after one of the several newly added timeouts. Resulting in the final WeakMap not holding onto any references.

let dog1 = {name: 'Snickers'};
let dog2 = {name: 'Sunny'};

var strong = new Map();
var weak = new WeakMap();


strong.set(dog2, 'Sunny is the 2nd best!');
weak.set(dog1, 'Snickers is the best!');

dog1 = null;
dog2 = null;

console.log(strong);
console.log(weak);

/*
Output
[Log] Map {{name: "Sunny"} => "Sunny is the 2nd best!"} (1)
[Log] WeakMap {{name: "Snickers"} => "Snickers is the best!"} (1)
*/

setTimeout(function(){
console.log("1200ms later... waiting for garbarge collection");
console.log(strong);
console.log(weak);
}, 1200);

setTimeout(function(){
console.log("3200ms later... waiting for garbarge collection");
console.log(strong);
console.log(weak);
}, 3200);

setTimeout(function(){
console.log("6200ms later... waiting for garbarge collection");
console.log(strong);
console.log(weak);
}, 6200);

setTimeout(function(){
console.log("12200ms later... waiting for garbarge collection");
console.log(strong);
console.log(weak);
}, 12200);

/* 
Output (eventually)
[Log] Map {{name: "Sunny"} => "Sunny is the 2nd best!"} (1)
[Log] WeakMap {} (0)
*/

Since garbage collection is not guaranteed to run, if you paste the code into the console while scrolling a JS heavy website, GC may actually run after the first timeout.

Sign up to request clarification or add additional context in comments.

2 Comments

This is still not guaranteed to show you your desired results, garbage collection happens when ever JS engine sees it is time to do so ... we can not define the time it does it.
I tried this same example and got the result described (I see weak getting empty at some point). I understand that I cannot determine when garbage collection will happen, but I can be sure that it will happen at some point, right? I modified this example and only changed all the setTimeouts for just one setInterval and result I get is that with setInterval the weakmap never gets garbage collected, and with setTimeout it always does (sometimes in the first one, sometimes in the third one, etc) Does seInterval somehow creates strong references?
1

Your code is totally fine, the problem is that it is not guaranteed to show you your desired results, garbage collection happens when ever JS engine decides that it is time to do so ... we can not define the time it does it. That's exactly why WeakMap does not support iteration and methods keys(), values(), entries(), because we don't know if those keys and values are there or not ... in other words we don't know if garbage collection has happened at that moment or not. If we have a loose reference, and it has not been garbage collected yet, these methods give us wrong results, and that's why they are disabled for WeakMap

Comments

0

In here you firstly created two seperate javascript objects called(reference variable names) dog1 and dog2:

    let dog1 = {name: 'Snickers'};
    let dog2 = {name: 'Sunny'};

And then you've created two different Map objects called strong and weak.

    var strong = new Map();
    var weak = new WeakMap();

In here you only set the value of the reference variable as the key for both Maps. And that map object is a seperate object and it doesn't have any connection with those reference variables "dog1" and "dog2" anymore after those values are put as the keys of that map objects.

   strong.set(dog1, 'Snickers is the best!'); // Here after value of dog1 doesn't affect map "strong"
   strong.set(dog2, 'Sunny is the 2nd best!'); // Here after value of dog2 doesn't affect map "strong"
   weak.set(dog1, 'Snickers is the best!'); // Here after value of dog1 doesn't affect map "weak"
   weak.set(dog2, 'Sunny is the 2nd best!'); // Here after value of dog2 doesn't affect map "weak"

So, after put the values of these variables in to the maps, even you assign null value to those reference variables it doesn't affect the map. Because they are seperate objects and don't depend on each other anymore.

   dog1 = null;
   dog2 = null;

So, even you check it after 1200ms also the result is same. Because making changes(by assigning null) to those reference variables doesn't affect the map.

   setTimeout(function(){
     console.log("1200ms later... waiting for garbarge collection");
     console.log(strong);
     console.log(weak);
   }, 1200);

And also you still have a reference variables strong and weak,so they are not still elegible for garbage collection.

Hope that following link will help you to learn garbage collection in JavaScript:

https://dzone.com/articles/memory-management-and-garbage-collection-in-javasc

2 Comments

This is completely not true, the only issue here is that we don't know when does garbage collection happen. We only know that WeakMap will let go of unreferenced keys when the engine does garbage collection
What if I delete the key from the Map, i.e. map.delete(key), or map.clear()? Will that key be garbage-collected afterwards?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.