Still finding some memory issues with Seam Remoting and IE6
pgmjsd Aug 5, 2008 5:36 PMI posted something about this a while ago in the old forums here.
Basically, there still seem to be some memory issues that arise when invoking lots of Seam Remoting methods in IE6. I've made a simple test page that invokes a single SFSB method over and over again by invoking the method inside it's own callback function. On my test machine this seems to work until about 30k calls, then IE6 puts up an alert saying there is not enough memory to complete the operation
.
Has anyone else encountered this?
We have a patch that seems to fix this, but it's kind of ugly. Basically we wrap the request and the callback in a separate object and put those in an associative array. I'm wondering if anyone knows of a better way to do this.
// An object that holds the request and the callback function ReqEntry(req, callback) { this.req = req this.callback = callback } // Global array that requestCallback can use. var REQ = new Array(100); var REQ_COUNTER = 0; Seam.Remoting.sendAjaxRequest = function(envelope, path, callback, silent) { Seam.Remoting.log("Request packet:\n" + envelope); if (!silent) Seam.Remoting.displayLoadingMessage(); var asyncReq; if (window.XMLHttpRequest) { asyncReq = new XMLHttpRequest(); if (asyncReq.overrideMimeType) asyncReq.overrideMimeType('text/xml'); } else asyncReq = new ActiveXObject("Microsoft.XMLHTTP"); // var rcb = Seam.Remoting.requestCallback; // asyncReq.onreadystatechange = function() { // if (rcb) rcb(asyncReq, callback); // } // Put the request into the array. if (REQ_COUNTER >= REQ.length) REQ_COUNTER = 0; var reqIndex = REQ_COUNTER++; REQ[reqIndex] = new ReqEntry(asyncReq,callback); // Pass the index to the callback. asyncReq.onreadystatechange = new Function("Seam.Remoting.requestCallback(" + reqIndex +");") if (Seam.Remoting.encodedSessionId) { path += ';jsessionid=' + Seam.Remoting.encodedSessionId; } asyncReq.open("POST", Seam.Remoting.resourcePath + path, true); asyncReq.send(envelope); return asyncReq; } Seam.Remoting.requestCallback = function(reqIndex) { // Get the request and the callback from the array. var req = REQ[reqIndex].req; var callback = REQ[reqIndex].callback; if (req.readyState == 4) { try { var inScope = typeof(Seam) == "undefined" ? false : true; if (inScope) Seam.Remoting.hideLoadingMessage(); // Don't need this. // req.onreadystatechange = function() {}; if (req.status == 200) { if (inScope) Seam.Remoting.log("Response packet:\n" + req.responseText); if (callback) callback(req.responseXML); } else alert("There was an error processing your request. Error code: " + req.status); } finally { REQ[reqIndex] = null; // Memory cleanup - Seam.Remoting.sendAjaxRequest creates a JS/COM/JS circular reference in IE by // making a closure and then pointing the asyncRequest at it. JavaScript is pointing at the // COM object (asyncReq), and the asyncReq COM object now points at a JavaScript object (the closure). // Here is the code: // asyncReq.onreadystatechange = function() {Seam.Remoting.requestCallback(asyncReq, callback); } // Since IE cannot GC the two interlinked object, we need to help out by forcibly deleting the // closure. delete req.onreadystatechange; if (Seam.Remoting.batchAsyncReq == req) { delete Seam.Remoting.batchAsyncReq.onreadystatechange Seam.Remoting.batchAsyncReq = null; } } } }
Simply deleting the onreadystatechange doesn't seem to work. I'll keep experimenting.