Isotope (leak free)
Isotope is a cool jQuery plugin that uses lots of other peoples' code to do lots of fancy animated arrangement, filtering and sorting. Unfortunately, it also leaks memory like a fucking sieve, and its author has expressed a complete lack of interest in remediating this situation despite having already authored a fix, so here's a fork for people who will get fired if they let their users' browsers crash for the sake of eye candy because they're not paid to build standalone corporate vanity pages for ad agencies.
In a word: Expandos. Despite being the scourge of all web programming for many a year (remember why everyone ran away from Prototype screaming?), they're occasionally necessary in cases where you really, really need persistent data attached to a specific DOM object. Isotope certainly requires this for much of its state awareness, so it keeps track of lists of atoms--which are basically cutesy synonyms for DOM objects.
filter) directly to these expando lists. Every jQuery selector operation returns an array with an extra
prevObject attribute. This attribute contains the complete result set of the selector--including the actual DOM objects selected--thusly supplying the magic necessary for its amazingly popular chaining mechanism to work.
Check it out on your console:
One of many offenses littered throughout the Isotope code would look like:
this.$allAtoms = this.$allAtoms.not( $content );
Let's think about what that means for a minute. We've got ourselves an Isotope-ified DOM object--for all intents and purposes:
this--and it's got some expando data attached to it called
$allAtoms, which is a list of all of
this's child nodes that Isotope has installed itself. We're running
not in order to filter something undesireable out of it and re-assigning the result of that directly to
The result of that
not contains another
prevObject attribute, which contains the result of jQuery's selection efforts. Again, that will be an array of child nodes of
this in every case, so
this will be retaining nested chains of cyclical references to those elements no matter how many times they're removed.
But it gets worse because this re-filtering and re-assignment process happens repeatedly and the cyclical references they produce predictably snowball. After just a few Isotope insertion/removal cycles, you'll have
and so on and so forth. Don't believe me? Ask Chrome's heap inspector:
Every one of those detached elements has outlived its usefulness and will never be seen again, but since all of their
If we're dealing with complicated nodes full of canvases and whatnot, you can easily build a staircase to 300MB of RAM consumption or more in just a few minutes of application use if you're adding and removing things on an ongoing basis.
Upon reading that comment, four engineers proceeded to slap themselves in unison. It's an honest mistake, but refusing to fix it is honestly, offensively stupid.
The unfortunate reality is that the more you use Isotope, the more shit you leave floating around in browser memory. The more shit you leave floating around in browser memory, the slower your app runs. You'll probably crash the whole goddamned browser, too, but hey, why would a rockstar ninja Twitter employee need to take that seriously? Computers have all the memory in the world these days and there just aren't enough hours in the day to blog about golden ratios and solve problems that don't involve helping deviant miscreants share seven second iPhone videos of their misshapen genitalia with the world; fuck responsible coding and gimme my $50. P.S. What's a leak?
The fix is simple: STOP ASSIGNING RAW JQUERY SELECTOR RESULTS TO EXPANDO PROPERTIES ON THE THINGS THEY WERE SELECTING! Really. That's all it takes. It's not even a heavily guarded industry secret or anything. Here's a really long, really thorough paper about it from IBM:
After plugging this horrible hole, things look much better. When GC runs, all the abandoned content is reaped exactly as it should be:
An admittedly better solution would be to just stop using Isotope, but we all have to ship at the end of the day, and the 20+ hours I wasted tracking this idiocy back to its source was ultimately less expensive than replacing the functionality I needed with something more specialized.
Linters can only do so much, kids.
Original work Copyright (c) 2011-2012 David DeSandro / Metafizzy LLC and all the other people he copied and pasted from.
And here's my license which entitles me to use all of this code in any commercial project I like:
Dec 7, 2012 10:56:20 PST | Receipt No: 2542-5500-0733-6758 Hello Nathan Duran, You sent a payment of $25.00 USD to Metafizzy. This charge will appear on your credit card statement as payment to PAYPAL *METAFIZZY. ---------------------------------------------------------------- Merchant information: Metafizzy email@example.com http://metafizzy.co Instructions to merchant: None provided ---------------------------------------------------------------- Payment details ---------------------------------------------------------------- Description: Isotope Commercial License, Item #: 13620, Unit price: $25.00 USD Quantity: 1 Amount: $25.00 USD Total: $25.00 USD Receipt No: 2542-5500-0733-6758 Please keep this receipt number for future reference. You'll need it if you contact customer service at Metafizzy or PayPal.