Is it correct that this code causes a memory leak in the browser?
/**
* @param {Canvas2DRenderingContext} ctx
* @param {string} url
*/
function loadImageDrawIntoCanvas(ctx, x, y, url) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img, x, y);
}
img.src = url;
};
My understanding is that because img is a DOM element and because I'm attaching JavaScript to it with img.onload
the browser will never garbage collect this. To correct that I'd need to clear img.onload
as in
/**
* @param {Canvas2DRenderingContext} ctx
* @param {string} url
*/
function loadImageDrawIntoCanvas(ctx, x, y, url) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img, x, y);
img.onload = null; // detach the javascript from the Image
img = null; // needed also so the closure doesn't keep
// a reference to the Image?
}
img.src = url;
};
It should not be a leak, as long as it's implemented correctly by the browser.
Old versions of Internet Explorer (7 and earler) had a GC that couldn't deal with circular references between JS and DOM nodes. There are a lot of guides out there that suggest clearing event listeners before removing DOM nodes because of this, and jQuery does this automatically. (NB: Other browsers might have had fautly GCs at some point, but old IE is the famous one.)
The interesting part here is that the GC needs to know if onload
will be fired again in the future or not.
I just tried rendering 275 MB of images to a canvas using code similar to what you posted, and Chrome does not leak. (By comparison, if I store the images in an array outside of the loop, then 275 MB are retained.) Firefox might leak [some?], but it's hard to tell because its memory overhead is much higher than Chrome's.
Why?
onload
and loadImageDrawIntoCanvas
both complete execution and no remaining references to the img
remain.img
when you call img.src=
, and decrementing it once onload
is fired. Chrome has two tests for these sorts of leaks (1, 2).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With