Skip to content

Instantly share code, notes, and snippets.

@rwaldron
Created May 9, 2011 22:54
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rwaldron/963596 to your computer and use it in GitHub Desktop.
Save rwaldron/963596 to your computer and use it in GitHub Desktop.
Example of WeakMap usage. Run in Firefox Nightly (>6.x)
var k = {}, v,
w = new WeakMap();
w.set( k, "value" );
console.log(
w.get( k )
);
// ...At some point the program no longer needs this
k = null;
// The es-labs implementation will return undefined, here:
// http://code.google.com/p/es-lab/source/browse/trunk/src/ses/WeakMap.js?r=491
// The current FF6.x implementation throws an exception "value is not a non-null object"
if ( w.get( k ) ) {
console.log(
w.get( k )
);
}
@SlexAxton
Copy link

Isn't this just 'Map' usage?

@rwaldron
Copy link
Author

rwaldron commented May 9, 2011

This is from http://wiki.ecmascript.org/doku.php?id=harmony:weak_maps&s=obj . Also, according to folks in #jslang there is possibility for introduction of a Map api itself as well.

@BrendanEich
Copy link

It's not Map, because if you set key = null then the WeakMap entry will be GC'ed (along with any other unreachable entries reachable in cycles from key's value -- say it's not "foo" but another object whose refs go away). Map has a strong ref to every key and value, and it's easy to make memory leaks by accident.

/be

@SlexAxton
Copy link

Right, but this example is ambiguous, if I understand things correctly (shaky grounds already).

A better example between the two might be something along the lines of the following:

var strongKey = {},
      s = new Map();

s.set( strongKey, "foo" );

s.get( strongKey ); // foo

// Garbage collection happens
s.get( strongKey ); // still 'foo'


var weakKey = {},
     weakKey2 = {},
     w = new WeakMap(),
     myApp = {
        init: function () {},
        keyRef : weakKey2 // <-- a strong reference
     };

w.set( weakKey, 'bar' );
w.set( weakKey2, 'baz' );

w.get( weakKey ); // bar
w.get( weakKey2 ); // baz

// Garbage Collection Happens

w.get( weakKey ); // undefined
w.get( weakKey2 ); // still 'baz' because of the strong reference

Again, that could be totally wrong, but that's the way I currently understand the difference.

@SlexAxton
Copy link

I see how I could be getting that wrong, though. Is it only garbage collected when weakKey is set to null (instead of just when it has no strong references, like I have in the above example)?

@BrendanEich
Copy link

Right, no refs left. JS does not have weak pointers (aka weak references) by which you might observe that something has become garbage. That leaks the non-determistic GC schedule and creates inter-operation bugs (different implementors do GC differently). WeakMaps (originally "Ephemeron Tables", based on the Smalltalk Ephemeron work for all collections, which invented the concept of a conditionally-weak key with value pair) avoid this ND-leak and avoid memory-leaks.

/be

@SlexAxton
Copy link

Ah, in my example I missed the fact that there is still the weakKey strong reference (naturally). But the original example would work just as well with Map since he never cleans up the key reference, no? I guess my only objection to using it as an example is it could be dangerous to use a weakMap like that if you don't expect things to get garbage collected. Though since they aren't enumerable and there are no other weak references possible, I suppose it'd be pretty difficult to get into a bad spot and lose a key/val pair that you didn't intend to lose. Perhaps just less ambiguity just for education's sake would help in a WeakMap example.

@rwaldron
Copy link
Author

@BrendanEich I just added another example, is this an accurate example of the GC behaviour?

@SlexAxton
Copy link

Since the div variable still is referenced to a dom element, even though it's not in the body anymore, it wouldn't get garbage collected.

@BrendanEich
Copy link

@SlexAxton: WeakMap is not dangerous, because you'll "lose" entries for keys you've already lost, so how could you look them up again ever? If you expect strong refs then yeah, use Map, but try to construct a program where this matters. You can't, cuz you'd need to keep the key alive with a strong ref to tell that it was in the WeakMap.

@rwldrn: see above -- the key is still alive so div is kept alive too. If you set both key and div to null around line 14, and then force a GC, then you can't look in the table (you nulled key, no way to look up and no way to for-in over keys still there) but you can be sure that the div is gone too. Our WeakMap may have debug-only enumeration support to test this.

/be

@SlexAxton
Copy link

@be got it. I tried to walk through that logic rather poorly, above. dherman implied that Map was being heavily considered as well. Is there a reason we'd ever want Map over WeakMap? And if not, why not just called WeakMap -> Map - and just have it behave nicely with GC? (and thanks for your patience)

@BrendanEich
Copy link

It's a good q, we have considered adding only WeakMap to Harmony, and Map and Set are not yet in harmony:proposals. But WeakMaps cost noticeably more in some applications than Maps, and if you want strong refs and that cost matters, then you'll grow to hate Map=WeakMap. So we're considering Map (and Set, which is just Map with key only, no value).

/be

@rwaldron
Copy link
Author

@BrendanEich So, that's exactly what I expected, except that I only saw one log line - because I didn't notice the tiny "2" on the end of the line (incidentally, I was also pulled over sitting in the back seat of my Jeep when posted that - my phone had buzzed alerting me of the first few comments and couldn't wait until I got home) In a nutshell: rush job b/w a good story.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment