MooTools & Garbage Collection
I’ve been working on a MooTools class for the past couple of days that makes large data tables scrollable. When the page loads, it checks to see if any data tables are larger than the scrollable area of the window. If there are tables like this, it puts the table into a scrolling div and copies the header and footer areas above and below the scrolling div, respectively. It also has the options of making the rows alternate colors and making the table rows sort when the headers or footers are clicked. I had it working quite well, but there were some performance issues.
The table I was testing with had 429 rows of 16 columns. This is a total of 6864 cells. I was taking advantage of MooTools’ getElementBySelector in many places because I needed to find th and td cells within the tbody, thead, and tfoot elements separately. This created some problems when the page unloaded. On Firefox, it was taking over 7 seconds just to leave the page. This obviously was unacceptable.
I was having trouble figuring out what the exact problem was. I’m having done a lot of Javascript debugging, and have done even less performance profiling. Luckily, the Firebug plugin to Firefox was a huge help. In fact, I don’t know how I would have figured out the problem if I hadn’t had it. I turned on profiling then refreshed my page. Firebug told me that the ‘remove’ method of the MooTools Array object was taking up all of the time. I wasn’t using the remove method, so I figured there must be some sort of garbage collecting going on in MooTools. After posting to the MooTools forum, I got the answer. Apparently, whenever you use any of the MooTools that returns a DOM node, it extends those nodes with the special MooTools methods. This means that if you use $, $$, getElementsByClassName, or getElementsBySelector, every node that is returned is extended by MooTools and must be garbage collected.
In my table, I had thousands of cells that I was accessing to implement various features. Every one of those cells was being extended and had to be garbage collected. By the time my script was finished, I had over 7,000 objects to be garbage collected when the page unloaded (as seen in the Garbage.elements object under the DOM tab in Firebug).
While the getElementsBySelector method is very handy, it wasn’t going to work for me because of the extreme number of cells in my table. I ended up rewriting much of my code to use the standard getElementsByTagName method to get around the issue. This made the code quite a bit uglier, but I guess most optimizations do. The lesson today is to be careful when using methods that extend nodes in MooTools. While MooTools is really nice, there can be too much of a good thing. I’ve heard that MooTools 1.2 does memory management in a very different way, so hopefully the severity of this type of situation will be reduced in the future.
