Feeds:
Posts
Comments

Archive for April, 2005

Arghhh…

In my day job I work for a company that’s creating a desktop application that uses the Mozilla framework. This means XUL pages with lots of JavaScript. I’ve got a certain page that appears to leak memory like a seive. Oh, and I mean that. I can set up a situation in which it will leak 10 MB of memory every minute. Major issue.

I think I’ve figured out what the problem is, but I have not a clue how to fix it.

Here’s the deal. We interface with a COM object (but an XPCOM object would have the same problem, so if anyone actually reads this, MS bashing will only show you to be an idiot in this case). In the JS code I’m setting up a callback with the COM object (think event sink). So, an event occurs within the COM object and it calls back to my JavaScript code. Sounds simple enough, but there in lies the problem.

The callback is sent data indicating what has changed, but isn’t sent the COM object on which the data changed. So, I tied this information to the callback using a closure (it would take to long to explain, but simpler methods aren’t readily possible for me to use, and I believe they’d result in the same issue any way). This results in a circular dependency. The COM object refers to the JS function/object (functions are objects in JS) through the sink while the JS function/object refers to the COM object through the closure. Some folks might think this isn’t an issue since JS is garbage collected and can deal with circular references. But things aren’t that simple, and you’ll just have to trust me that since the lifetime of the two objects are controlled by different mechanisms, this circular reference means that neither object may be collected.

People have known about this "bug" in IE for some time (Google search on the topic), and there’s a lot of rants about MS being in leage with the devil because of it. However, you shouldn’t be so quick to attack. When using Mozilla and their ActiveX plugin I have the same issue. And before you blame ActiveX for the problem, I’ll point out to you that Mozilla has the same issue with it’s own XPCOM components. There’s probably a solution that could be implemented by both MS and Mozilla to make this a non-issue for developers, but it’s a non-trivial problem and neither of them have done so.

So, basically, my problem can be boiled down to code something like this.

var comObj = new GeckoActiveXObject(‘SomeLib.SomeComObject’);

function Advise( comObj, func ) {
var callback = {
OnUpdate: function( data ) {
func( comObj, data );
}
}
return comObj.AdviseCallback( callback );
}

function Callback( comObj, data ) {
// update accordingly
}

var cookie = Advise( comObj, Callback );

In ‘Advise’ the ‘comObj’ COM object is set to reference the ‘callback’ object within the ‘AdviseCallback’ method. The ‘callback’ object in the mean time references the ‘comObj’ because of the JS closure mechanism. I *need* this closure. I’ve tried numerous things, but I can’t quite figure out how to break this cycle.

EDIT:

Evidence, from Mozilla even, that the error exists even in Mozilla.http://www.mozilla.org/scriptable/avoiding-leaks.html.

Read Full Post »