243 karma · joined December 4, 2010
I just submitted a PR to the main Meteor docs pointing there: https://github.com/meteor/docs/pull/164
(There are other features too, which I entirely ignore without missing anything. In fact, other than "there are some HTML buttons in the email", which will probably also eventually have an option to turn off, our transition from our prior mailing list service was almost unnoticeable for somebody like me who didn't want to use the extra features. And that's a compliment.)
I really appreciate the work Arunoda has done on smart collections; my implementation and his package have both learned from each other. That said, there are a number of subtle race conditions involved in synchronizing queries between the oplog and the main database, and working out all the little details as carefully as possible has taken time!
If you are using Chrome, open the Developer Tools and click the gear
icon in its lower right corner. In the General Settings panel, turn
on 'Enable source maps'.
If you are using Firefox 23, go to `about:config` and set the
`devtools.debugger.source-maps-enabled` preference to true.
(The preference should be on by default in Firefox 24; versions
older than 23 do not support source maps.)A world-class JavaScript environment like V8 is far past "the simplest thing that is correct according to the spec".
In fact, the JavaScript spec doesn't actually define anything about garbage collection! You can create a compliant ECMAScript-262 runtime that literally never collects any garbage ever. That's certainly the simplest correct thing. But it's a bad idea!
V8 already goes to the trouble of figuring out whether or not a given variable needs to be stored in the lexical environment or not. Specifically: variables that are not used in ANY closures and where there is no eval in sight can be stored outside of the lexical environment. This is great, and better than many similar programming language environments offer.
It just would be even better if they went one step farther.
If you run these on your own machine and peek at the RSIZE, it stays constant (well, the first grows slowly due to `logIt`).
http://play.golang.org/p/A5Pz-3kthP http://play.golang.org/p/RnXr_jB5Qh
But the original bug that led to this discovery involved a data structure that shouldn't have leaked at all. I've updated the post to show it; duplicated here since GitHub Pages seems to cache posts pretty aggressively.
var theThing = null;
var replaceThing = function () {
var originalThing = theThing;
// Define a closure that references originalThing but doesn't ever actually
// get called. But because this closure exists, originalThing will be in the
// lexical environment for all closures defined in replaceThing, instead of
// being optimized out of it. If you remove this function, there is no leak.
var unused = function () {
if (originalThing)
console.log("hi");
};
theThing = {
longStr: new Array(1000000).join('*'),
// While originalThing is theoretically accessible by this function, it
// obviously doesn't use it. But because originalThing is part of the
// lexical environment, someMethod will hold a reference to originalThing,
// and so even though we are replacing theThing with something that has no
// effective way to reference the old value of theThing, the old value
// will never get cleaned up!
someMethod: function () {}
};
// If you add `originalThing = null` here, there is no leak.
};
setInterval(replaceThing, 1000); > (function () { var x = 5; eval("console.log(x)"); })()
5
> (function () { var x = 5; var e = eval; e("console.log(x)"); })()
ReferenceError: x is not definedSo you should be able to statically determine if this is the case, and it's not here.
It was that code to replace a certain type of object (a Spark renderer) with a new instance of that object accidentally ended up with a reference to the preceding renderer in a closure assigned somewhere on it, even though that particular closure didn't actually use that reference.
So instead of replacing renderer #N with renderer #(N+1) and GCing #N, we ended up with a stream of renderers which never could be GCed... even though the reference keeping the old ones alive was literally impossible to ever use.
The surprise is that `logIt` holds on to the giant `str` object in its environment, despite the fact that there is literally no way for the `str` variable to ever be used again.
V8 is smart enough to not make `logIt` hold on to `str` if there are no closures at all which refer to `str`. It's the introduction of the unrelated `doSomethingWithStr` closure that forces `str` into the lexical environment.