Skip to content

Instantly share code, notes, and snippets.

@fearphage
Forked from lsmith/About this gist
Created August 1, 2009 06:54
Show Gist options
  • Select an option

  • Save fearphage/159589 to your computer and use it in GitHub Desktop.

Select an option

Save fearphage/159589 to your computer and use it in GitHub Desktop.
This gist aims to prove or disprove the assertion made here[1] and linked on
Ajaxian[2] that dynamic script requests, or more specifically JSONP requests,
leak memory in all modern browsers.
The specific setup is a 200ms interval that requests an uncached script pointed at
the simple php file. This file in response sends the following string:
update()
This is not technically a JSONP response, since the would-be callback is executed
without arguments. However, memory footprint results can be gauged on generic
script content rather than focused on the JSONP pattern.
With all versions of this setup in the gist history, there IS a memory leak.
Log:
version 1: use a simple xbrowser getScript in the setup described
version 2: move the script node clearing code out of the getScript function to test
for closure related leakage. Add the "About this gist" file to track progress.
version 3: formatting updates to "About this gist" file.
version 4: testing setting defer to true (no change)
version 5: wrapping node creation in try/finally to null node references (no change)
version 6: calling script.clearAttributes() if available (IE) before node removal. Interestingly, this did seem to flatline the mem footprint until about 500 requests, at which point memory climbed rapidly.
version 7: per Andrea Giammarchi's destroy suggestion[3][4], added while loop to remove
all childNodes before removing from the DOM (no change)
version 8: moved the clearAttributes and childNode removal after the script node
removal. Again, seemed flat until ~400 requests, then shot up.
version 9: replaced clearAttributes call with manual iteration of script props,
assigning each to null inside a try/catch because IE throws errors. Memory
consumption shot up faster than any prior configuration.
1. http://neil.fraser.name/news/2009/07/27/
2. http://ajaxian.com/archives/dynamic-script-generation-and-memory-leaks
3. http://webreflection.blogspot.com/2009/04/drip-under-control-via-another-ie.html
4. http://ajaxian.com/archives/dynamic-script-generation-and-memory-leaks#comment-274727
<?php
header("Cache-control: no-cache");
header("Expires: -1");
header("Content-type: text/javascript");
echo "update()"
?>
<!doctype html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<p id="inc">0</p>
<p id="remaining">0</p>
<button id="go">Start</button>
<script type="text/javascript">
var timer = null,
update_int = null,
count = 0;
// Executed by the requested scripts
function update() { ++count; }
function clearScript() {
var hasReadyState = ('readyState' in this);
if (!hasReadyState || /loaded|complete/.test(this.readyState)) {
this[hasReadyState ? 'onreadystatechange' : 'onload'] = null;
this.parentNode.removeChild(this);
for (var k in this) {
try {
this[k] = null;
}
catch (e) {}
}
}
}
function getScript(U){
var h = document.documentElement.firstChild,
s = document.createElement('script');
try {
s[('readyState' in s) ? 'onreadystatechange' : 'onload'] = clearScript;
s.defer = true;
s.src = U;
h.insertBefore(s,h.firstChild);
}
finally {
s = h = null;
}
}
document.getElementById('go').onclick = function () {
if (timer) {
clearInterval(timer);
timer = null;
update();
clearInterval(update_int);
update_int = null;
this.innerHTML = "Start";
} else {
timer = setInterval(function () {
getScript('script_leak.php?x='+(new Date().getTime()));
},200);
update_int = setInterval(function () {
document.getElementById('inc').innerHTML = count;
document.getElementById('remaining').innerHTML = document.getElementsByTagName('script').length;
},1000);
this.innerHTML = "Stop";
}
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment