The leak is classic: introduce a dynamic script DOM element, let the script execute, then remove the DOM node. Rinse. Repeat. The problem is the DOM element will not free and I cannot see any circular reference. I've tried all the tricks and can't solve it. The leak exists in both ie 6-8 and firefox.
My kit does real time updates without requiring a page reload/refresh so the leak is bothersome and can grow quickly.
I have tried moving the node to a garbage pool DIV and setting the innerHTML to "". I have tried the destroy() approach. I have stood on my head and walked with my ears.
All you need are these two small files:
File 1 leak.js:
// all the file contains is this one comment line!
File 2 leak.html:
Code:
<html>
<SPAN id='leakid'><SCRIPT language='JavaScript'>
// CALLED EVERY 500 ms FROM TIMER
function getUpdate() {
var mySpan = document.getElementById('leakid');
// WHACK THE OLD ONE FROM LAST GO AROUND
var oldNode = document.getElementById('myUpdater');
if (oldNode) {
oldNode.parentNode.removeChild(oldNode);
oldNode = null;
}
// LOAD A NEW ONE
var newNode = document.createElement('script');
newNode.type = 'text/javascript';
newNode.src = 'leak.js';
newNode.id = 'myUpdater';
mySpan.appendChild(newNode);
newNode = null;
mySpan = null;
return;
}
</SCRIPT></SPAN>
<BODY bgcolor="#4682B4" leftmargin="2" marginheight="0" marginwidth="0" topmargin="2" onload="getUpdate(); timerInterval = setInterval('getUpdate()', 500);">
</BODY></HTML>
The SCRIPT element does not support the standard core HTML attributes (id, class, style, title). Neither do BASE, HEAD, HTML, META, PARAM, STYLE and TITLE elements.
So, the SCRIPT element can not bear anid, so that there is nothing to be found using getElementById() method. As a result the SCRIPT element is not removed. Try to use getElementsByTagName() instead, and the index of the element within that collection.
Still leaks like mad. BTW it was finding the script using the getbyid. There has got to be a way to do this, right?
My original code remembered the child node from the createelement directly:
Code:
var myScript = null;
// CALLED EVERY 500 ms FROM TIMER
function getUpdate() {
var mySpan = document.getElementById('leakid');
// WHACK THE OLD ONE FROM LAST GO AROUND
if (myScript ) {
myScript .parentNode.removeChild(myScript );
myScript = null;
}
// LOAD A NEW ONE
myScript = document.createElement('script');
myScript .type = 'text/javascript';
myScript .src = 'leak.js';
myScript .id = 'myUpdater';
mySpan.appendChild(myScript );
mySpan = null;
return;
}
I have no idea, but did you try using global vars for the node objects so they are never 'held on to'....how do you know you're observing a memory leak? I couldn't observe anything (browser slowness, increased memory usage in the process) when I tested in firefox or IE on windows.
I've switched careers...
I'm NO LONGER a scientist,
but now a web developer...
awesome.
I can't say that this is the case, but I suspect that the problem is that you are removing the old script but you are not removing its children, who in essence become stranded, and are never removed.
The code within the <script> tags consists of one or more textNodes. Destroying the parent doesn't necessarily mean that they will be destroyed. And since you are doing this every half second I can see why it consumes more and more memory.
I believe you, but it leaks using any method I can see, that was just the most recent spin on things
In my previous response I posted code that just remembers the node added using a varaible. That too leaks. So does finding by tag. FOr the elements by tag I created a little div to hold the script and deleted all script tag items from it (and for god measure set the div inner HTML to ""). Leaks.
Originally Posted by Kor
About the id in SCRIPT tag:
"The core standard HTML/XHTML attributes (class, id, style, title) are not valid in base, head, html, meta, param, script, style, and title elements."
I tried that in the following way: Make a div just to hold the script. Then on cleanup time, remove any children of the script node and any children of the div.
but it still leaks. AAAARRRRGGGHHHH.
Code:
var myScript = null;
// CALLED EVERY 500 ms FROM TIMER
function getUpdate() {
var mySpan = document.getElementById('leakid');
if (scriptDiv== null) {
scriptDiv= document.createElement('DIV');
scriptDiv.id = 'scriptBucket';
scriptDiv.style.display = 'none';
document.body.appendChild(scriptDiv);
}
// WHACK THE OLD ONE FROM LAST GO AROUND
if (myScript) {
while (myScript.lastChild) {
myScript.removeChild(scriptNode.myScript);
}
if (myScript.parentNode != null)
myScript.parentNode.removeChild(myScript);
delete myScript;
myScript= null;
}
while (scriptDiv.lastChild) {
scriptDiv.removeChild(scriptDiv.lastChild);
}
scriptDiv.innerHTML = "";
// LOAD A NEW ONE
myScript = document.createElement('script');
myScript.type = 'text/javascript';
myScript.src = 'leak.js';
myScript.id = 'myUpdater';
scriptDiv.appendChild(myScript );
mySpan = null;
return;
}
Originally Posted by Tcobb
I can't say that this is the case, but I suspect that the problem is that you are removing the old script but you are not removing its children, who in essence become stranded, and are never removed.
The code within the <script> tags consists of one or more textNodes. Destroying the parent doesn't necessarily mean that they will be destroyed. And since you are doing this every half second I can see why it consumes more and more memory.
I have no idea, but did you try using global vars for the node objects so they are never 'held on to'....how do you know you're observing a memory leak? I couldn't observe anything (browser slowness, increased memory usage in the process) when I tested in firefox or IE on windows.
I had a typo in my second post in the thread, so I bet the javascript aborted.
*** removed my original thoughts because I just realized leak.js only contains a JavaScript comment ***
@Kor: While the HTML standard says the standard attributes don't apply to SCRIPT elements, you can still specify an Id and use getElementById to grab a reference to that node. That does work in browsers, even though it is technically invalid HTML.
Last edited by toicontien; 02-03-2011 at 06:36 PM.
[QUOTE=toicontien;1137274]The memory taken up by the script source of leak.js is probably not being garbage collected. Look at the code in that file, and see if any of that code is holding pointers to other objects in memory. That's probably the source of the "leak" and it's also probably the intended behavior of the browser. I'm not convinced the memory for the SCRIPT node is what's causing this behavior.
QUOTE]
Toicontien,
thanks. I removed all javascript from leak.js until it was just a single comment to explicitly remove that concern. So the script loaded is literally just a single comment line. Now in the application of course its a relevant script but I am just stripping away to identify the leak.
I did just think of something. I banged my head against a memory leak for a LONG time once, and discovered it was actually a result of having Firebug or the Safari/Chome debug tools open. Try disabling them and performing your test.
Bookmarks