Reputation: 1156
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!"}
*/
Upvotes: 4
Views: 2041
Reputation: 481
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
Upvotes: 1
Reputation: 567
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
Upvotes: 0
Reputation: 1156
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.
Upvotes: 2