Tuesday, July 25th, 2006

Biggest AJAX problem

Category: Ajax, Editorial

Spend any time with any language out there (Javascript, PHP, ASP, etc) and you’ll run into problems. Most of these can be resolved with a few tweaks here and there, but sometimes, things can get the best of you. Ajax code isn’t immune either, and with the addition of an outside content source, things can get pretty hectic pretty quickly. Remus Stratulat found this out firsthand when he had to track down a memory leak in his code – resulting in Firefox swallowing up 700MB of memory.

AJAX is becoming the new “de facto” standard in the web application industry. If you ask a JavaScript developer about what is the biggest problem of JavaScript programming it will probably tell you it’s browsers’ incompatibilities. In my opinion there is a worse problem then hacking your way around bugs and differences. That problem is represented by memory leaks.

He notes that, most of the time, Javascript can clean up after itself, freeing up variables and resources for other scripts to use. Unfortunately, Ajax causes a chink in the page’s armor – a way to let content in that could sometimes destroy the rest of the page (or just start clogging up the RAM on the machine until it grinds to a halt).

Checking your code is always a must, of course, but is there a way that problems like this can be handled at a more basic level?

Posted by Chris Cornutt at 7:51 am
29 Comments

+++--
3.9 rating from 44 votes

29 Comments »

Comments feed TrackBack URI

Doesn’t Google’s GWT solve the cross-browser problem
cleanly?

Comment by Edward — July 25, 2006

Right now almost all AJAX frameworks and libraries are hiding the cross-browser incompatibilities from the developer.

Comment by Remus Stratulat — July 25, 2006

No Alexandru, nothing will replace sound programming practices and resource allocation/de-allocation. Reloading the whole page every (pick an arbitrary number) clicks or actions would make for quite an inconsistent and frustrating user experience, not to mention make it much more difficult for the developer who has to deal with application and component level state (do you keep state on the client sometimes and then marshal it to the server for these total reloads, or do you send it to the server with every state changing action?). Truely scalable ajax apps will have to incorporate custom garbage collection to handle the cases of DOM fragment overwrites and circular references.

Comment by Ryan Gahl — July 25, 2006

Can any of you share some of the techniques you used to track down memory problems? I agree 100% that memory leaks not browser incompatibilities are what should (or already do) keep ajax developers up at night.. But the tools to identify and fix these problems are few and far between, and those that exist are not very sharp. I’m aware of Drip, and there was a similar tool for FF as I recall? What else is out there? Tools / testing and troubleshooting methodologies?

My experience has been that its largely a matter of poring over code, finding DOM nodes references that might not be removed properly, checking event handlers are removed.. but its long, laborious work with no guarantee at the end of it that you really found the important problems, or that you fixed them.

Comment by Sam Foster — July 25, 2006

The AJAX frameworks will have to provide the developer with the tools to allow him to handle this problem. The basics are there, if you add a listener you have the method to remove it. When you create DOM objects you must be able to destroy them.

Comment by Remus Stratulat — July 25, 2006

I just hope the debugging tools continue to get better and better. I honestly don’t know what I’d do without the DOM Inspector and Firebug…

Comment by rick — July 25, 2006

I use FireBug but that is not for leaks detection. Soon more capable tools must emerge or AJAX development will remain a guessing business regarding this problem.

Comment by Remus Stratulat — July 25, 2006

Could someone please let the readers of this site know why you refuse to fix the commenting system? Really, what is the reason?

Comment by Ryan Gahl — July 25, 2006

Probably to discourage the spamming engines at they will receive an error.

Comment by Remus Stratulat — July 25, 2006

Sam, the best way to prevent leaks is look at your architecture as a whole. The best “tool” is good application design from the bottom up. If you are poring through files that are filled with markup, server code, and javascript throughout, looking for all the individual places where there might be a circular reference or potential leak, then yes, you can never really be sure you got them all. If your design is clean, with good separation of concerns, and controls are componentized then memory management will fall right in.

Comment by Ryan Gahl — July 25, 2006

The moral of the story here is not “Javascript developers aren’t doing a good job of garbage collection”, it’s “Browser developers aren’t doing a godo job of garbage collection”.

There’s no malloc in JS, it’s supposed to be a gc language. These are interpreter bugs that JS coders are having to work around.

Comment by Peter Harkins — July 25, 2006

One of the biggest problems I see is that there is no (reasonable) way to removeEventListeners in JavaScript.

Imagine some DOM elements that have listeners attached. Then, the DOM elements are removed, but the events remain attached…

I had this kind of problems when implementing a simple tooltip engine, where after removing the target elements from the DOM, the tooltip elements were still there, and no GC engine would remove those…

So at the end, it’s a question of good programming and a good GC.

Bogdan

Comment by Bogdan Ripa — July 25, 2006

Hi Ryan,
I know about sound programming practices, but I’m in the web development business (selling tools), and I can assure you that there are very few developers and senior developers there, while there are millions of newbies that want to do Ajax and that are actually deploying live websites

As for the reloading experience, we’ve analyzed in depth the Gmail experience when doing Ajax navigation. While we suppose only data in exchanged with the server, the page refresh process is the following:
Change cursor to “waiting”Show Red Loading Label in the upper rightShow white pageShow new page
I presume that the experience for the user was ok as actually nobody saw this :)

And for managing the states, we’re trying to solve the application state problem in our framework, solving this developer problems automatically. But indeed, it was a very, very difficult problem to solve.

Let’s just wait and see how good web developers/newbies will get in learning advanced programming techniques, or whether the browsers will get better in improving the JS GC

Alexandru

Comment by Alexandru COSTIN — July 25, 2006

Yes, JavaScript is a GC language. And yes, some times the browser GC or JSVM does not do a good job in cleaning the memory. I found a reference about it in this article: http://www.bazon.net/mishoo/home.epl?NEWS_ID=1281

However, the job of a JavaScript programmer has become more difficult in the AJAX era and that is the focus of my article. In the old days a JavaScript programmer was comfortable enough in being sloppy with the objects he was creating as the browser was cleaning everything up when the page was reloaded. When you are developing a single page AJAX application everything is loaded and created in the same scope. If the programmer does not take care to “null” everything that he has created when he no longer needs it then you have a big problem. Not to mention about unregistering all the listeners from all the events. It is very easy to get lost in the referencing scheme. So unfortunately the JavaScript developers aren’t doing a good job of garbage collection.

There are 8 millions html developers and each one of them will think sooner or later to get his hand dirty with some AJAX. They will pull some content from the server and create a bunch of objects and register events to them. After that they will pull some more content from server and do the same thing on the same page. What do you think has happened with the objects he first created? They will continue to linger in a “no objects land” inside the JSVM, ghosts… memory leaks.

Comment by Remus Stratulat — July 25, 2006

@Peter: Even very good garbage collected languages will have cases where resources are being accessed outside of the managed environment, in which case there is no alternative other than the developer writing custom finalizers (dispose methods) on their objects, and ensuring that they get called when appropraite. For js UI components this amounts to setting DOM element references and event handler references to null. One approach, as I’ve alluded to, is creating a custom AJAX control garbage collector that handles this process in the background. Once that system is built into the application architecture, it makes it slightly easier for the developers; they just write the finalizer methods for each component and the system handles when those methods get called.

@Alexandru: Sorry, wasn’t implying you didn’t know good programming practices :-)… agreed that there are oh-too-many designers/amateurs trying to handle application development with very little concern for architecture. Even though much of the application has potentially migrated to the client, this does not mean we can do away with the developers, it just means the developers need to learn this environment, and let the designers do what they do best, design.

Comment by Ryan Gahl — July 25, 2006

Here at TIBCO in the TIBCO General Interface AJAX RIA toolkit, we addressed the memory issue for AJAX back in 2001. The solution we found was to implement an abstration layer for the native DOM, managed by a client-side controller in a MVC paradigm. Thus adding and removing from the higher level DOM, managed through the controller enabled the controller to manage clean up of objects and memory in a more predictable and manageable way. Keep in mind this technique was used to support Web applications that look and perform like desktop GUIs as opposed to slight enhancements here and there in the context of HTML pages (e.g. Client/SOA ajax as opposed to Enriched HTML page ajax). This “2 DOM” approach as early as 2001 was suffucuent to power chemogenomic drug disovery solutions deployed to the USFDA and major pharma companies. That solutions was very data instensive and loaded/unloaded about 180 various application modules over lengthy (multiple hour) sessions. There’s a recording including discussion about that solution here: http://www2.sys-con.com/webinararchive.cfm?registered=on&pid=61

Comment by Kevin Hakman — July 25, 2006

Forgive me for being a noob, but what exact cases are there where memory isn’t being deallocated properly? Previous comments allude to DOM nodes that are not in the document tree not deallocating when the fall out of scope. Is this really the case? If so, isn’t this primarily an issue with the browser-specific implementations of the JS GC?

In any case, it doesn’t appear that there’s an easy way of tracking such a thing with modern JS debugging tools…

Comment by Nick Husher — July 25, 2006

@Kevin: that’s interesting. I’d read about your 2 DOM approach before, but hadn’t really understood it in this context. This is the kind of thing I’m fishing for: real tried-and-tested patterns that address the core problem. The event cache is another – implemented in Dojo and Prototype among others. And higher level widgets are another – which provide a consistent interface which includes a destroy method that can get called automatically or as necessary to re-draw/re-purpose the screen. What else is out there?

My impression for the last year or so has been that a lot of work has gone into getting folks started with ajax, but much of the work that ensures success is still behind closed doors. Is this really critical competitive advantage that is being deliberately withheld? Or is it simply that most of us are still in early development phases and finding this stuff out as we go along.

As we each move from the general to the specific in our development, its understood that a lot of the lessons learned are exclusive to the particular application we’re working on. But many are not. I’m looking for good accounts of the end-game. The postings around the Yahoo Homepage change / @media presentation were valuable in providing candid information on the problems that team faced and how they solved them. Performance and memory management are bugbears that we all face. Are there any more good resources out there that address these issues?

Comment by Sam Foster — July 25, 2006

@Kevin: Interesting, I honestly fell by a very similar technique by my own accord (I swear), with DOM referencing and cleanup across incremental partial page updates (via componentized MVC model) abstracted, and a global GC system.

@Sam: The answer is yes and yes. Yes, much of this stuff is considered proprietary to those who have discovered it, packaged it, and are trying to sell it, and yes, it’s all part and parcel to the learning curve of this new frontier. As you move through what is possible, you start running into problems. Problems are nothing more than opportunities to find novel solutions. If you are like some, once you find those novel solutions, you see dollar signs :-). It’s not about hiding things from people on purpose to oppress them though, it’s about timing and opportunity.

Comment by Ryan Gahl — July 25, 2006

@Nick: I am primarily a Java developer. The Java GC does a very good job but even it can not solve all the problems. A good developer or a good architect should not overlook this problem any more.
No matter how good a GC will become there is a boundary that it will not cross and that boundary is cleaning objects that you are using. Defining that boundary is the biggest challenge a VM designer must tackle.
When the browser closes a page the line between used objects and unused ones is simple and clear. When the page resides in a browser for a longer period of time the GC may have a hard time in defining the used and unused references. If the developer does not take the necessary precautions in cleaning after himself the GC will not be able to perform its job.

Comment by Remus Stratulat — July 25, 2006

Hi,
could someone make it clear
1) Do you need to unset events binded with Event.observe() (prototype.js) Once the corresponding piece is refreshed with ajax call?
2) What is cross-browser way to unload iframes? (and check if they’re loaded)

Thanks in advance

Comment by Mark Sergienko — July 25, 2006

Mark,
1) Using prototype as the example, and assuming “this” is an object representing your component/control/widget… notice that you should always create a handle to your event handling functions, so you can properly dispose of them using Event.stopObserving (and then remember to set the handle to null to remove all references). You can dispose of the event handlers and DOM references before you make the AJAX call, which must be a synchronous operation to be reliable, OR you can implement a DOM reference abstraction layer and pass the cleanup process to an asynchronous garbage collector object. The latter is better overall for performance of the app, but the former is easier to implement.

this.someEventHandler = this.doSomething.bindAsEventHandler(this);
Event.observe($('someElement'), "click", this.someEventHandler);

//..and then later in the dispose method, either before the call which would result in this DOM fragment being over-written, or asynchronously via the DOM referencing abstraction/GC layer...

Event.stopObserving($('someElement'), "click", this.someEventHandler);
this.someEventHandler = null;

Comment by Ryan Gahl — July 25, 2006

I actually agree with you on your final point

Comment by Personal Interactive — July 25, 2006

Ryan,
Thanks alot, i also found an article on that, and almost refined all of my code by the time,
http://www.archivesat.com/Rails_spinoffs/thread392813.htm explains the pattern,
so I’m going to delete references as well, and so far can keep FF memory on level, though IE still have some glitches. (Mainly i think because the way i implemented Google Maps Api)

Thanks for explanation again

Comment by Mark Sergienko — July 25, 2006

Mark, did you notice I wrote that article :-)

Comment by Ryan Gahl — July 26, 2006

Ryan,
hehe, nice job buddy.
I’ll write off on results..
And one more question
If you do like
Event.observe(“element”, “click”, this.myhandler.bindAsEventListener(this));
and then
Event.stopObserving(“element”, “click”, this.myhandler.bindAsEventListener(this));
Does it make a huge difference without saving event handlers and then reseting them?

Thanks again.

Comment by Mark Sergienko — July 26, 2006

Mark, sorry so late in replying to that last Q… I don’t think that will work, bud. I believe Event.stopObserving (also meaning the underlying DOM2 event model) requires a handle (or pointer) to the same function as the observe method (same memory address) to work correctly. Remember bind() and bindAsEventListener() return closures (anonymous functions), so you’d be passing in a newly created and different function (meaning different memory address) into the stopObserving method than you did to the observe method. I believe your method would work if you were passing in globally scoped, static function names. As with anything, try it and analyze the results to get an understanding of what’s going on under the covers :-).

Comment by Ryan Gahl — July 27, 2006

hdv2pvs7ish5

Comment by 7blfrsglg — August 17, 2006

I get some bad cases of this. I run a plugin in firefox that restores my session each time I start the browser again. This becomes somewhat like not closing your browsers for weeks on end and when I keep tabs with AJAX apps open in them running that long them memory use is huge!

Comment by Robbie MacKay — August 21, 2007

Leave a comment

You must be logged in to post a comment.