Page 1 of 2 12 LastLast
Results 1 to 10 of 18

Thread: setTimeout, closures, and IE memory leak help

  1. #1
    Join Date
    Aug 2004
    Posts
    10,143
    Thanks
    3
    Thanked 1,008 Times in 993 Posts
    Blog Entries
    16

    Default setTimeout, closures, and IE memory leak help

    Hi:
    I'm trying to understand how to resolve an IE memory leak that occurs in the following general situation. Basically, if I use a closure inside setTimeout() to call an object instance method repeatedly, in which the method accesses the .innerHTML property of an element to modify it's HTML, a leak occurs in IE. For example:

    Code:
    <div id="numberdiv">holder</div>
    
    <script type="text/javascript">
    function timemachine(offset){
    this.offset=offset
    this.display()
    }
    timemachine.prototype.display=function(){
    //Use the innerHTML property to assign rich HTML to an element, in combo with closure- leak in IE!
    document.getElementById("numberdiv").innerHTML='<p><b>'+this.offset+new Date().getSeconds()+'</b></p>'
    var _this=this
    //Closure below, no leak by itself
    setTimeout(function(){_this.display()}, 1000)
    }
    var sample=new timemachine(5)
    </script>

    Apparently it's the closure coupled with the rich HTML assignment that creates the leak. I've tried a few standard techniques to plugging the leak, but nothing has worked. Anyone know of an elegant solution that doesn't require "re-wiring" everything? Any pointers appreciated.

  2. #2
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    They always tell you to create another closure to avoid the IE memory leak. However, I've been running your code for awhile now and memory seems constant (physical, kernel (paged and nonpaged)). That's with IE 7 though.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  3. #3
    Join Date
    Aug 2004
    Posts
    10,143
    Thanks
    3
    Thanked 1,008 Times in 993 Posts
    Blog Entries
    16

    Default

    I'm testing this in IE6, though I've seen cases of leaks even in IE7, which includes the above example.

    They always tell you to create another closure to avoid the IE memory leak.
    I'd love an example of this. I've tried the double closure route, though I must have gotten lost in my own code, because it didn't do anything in halting the perpetual memory increase.

  4. #4
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    I'll have to have a look at this again later as I am winding down for now but, since I don't see the leak here, it would be hard to test. Any particular type of memory that you see as beng most affected? Also, just a thought, try switching to interval:

    Code:
    <div id="numberdiv">holder</div>
    
    <script type="text/javascript">
    function timemachine(offset){
    this.offset=offset
    this.display()
    }
    timemachine.prototype.display=function(){
    //Use the innerHTML property to assign rich HTML to an element, in combo with closure- leak in IE!
    document.getElementById("numberdiv").innerHTML='<p><b>'+this.offset+new Date().getSeconds()+'</b></p>'
    var _this=this
    //Closure below, no leak by itself
    if(!this.counting)
    this.counting=setInterval(function(){_this.display()}, 1000)
    }
    var sample=new timemachine(5)
    </script>
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  5. #5
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    Anyone know of an elegant solution that doesn't require "re-wiring" everything?
    It's already inelegant by the use of innerHTML. Does the leak still occur using DOM methods?
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  6. #6
    Join Date
    Aug 2004
    Posts
    10,143
    Thanks
    3
    Thanked 1,008 Times in 993 Posts
    Blog Entries
    16

    Default

    Thanks guys. I haven't tried switching over to DOM methods yet (versus innerHTML), mainly because I need the script to run ASAP, without having to wait for the DOM or document to load fully first. Also, this serves as a good chance for me to clarify my understanding of how leaks occur in IE.

  7. #7
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    So long as the parent element is loaded, the DOM usually doesn't mind if the page isn't finished yet.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  8. #8
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    It is my opinion that the vagaries of the IE memory leak are such that one can only understand it in so far as it either is a problem with a particular bit of code or it is not. That being said there are principles to follow when one is encountered.

    I'm willing to play with this code to see what might be done to avoid a leak when using it. To do so I would need to know what type or types of memory you see are being affected by it. In taskmanager there are several indicators of memory usage:

    • PF Usage

    • Physical Memory (K)
    • Total
    • Available
    • System Cache
    • Kernel Memory (K)
    • Total
    • Paged
    • Nonpaged


    Which of these indicators are you seeing the problem with or are you using another utility to measure the leak?

    There are other considerations:

    • Does simply running the code cause the leak?
    • Does reloading the page cause the leaking and/or more leaking?
    • Does unloading the page restore the memory or must one close the browser?


    Notes: I think Twey's idea of using the DOM is worth a shot but, it usually isn't one of the methods mentioned for resolving these leaks. That doesn't mean that it will not do the trick in this case.

    Adding a closure could be as simple as:

    Code:
    function timemachine(offset){
    this.offset=offset
    this.display()
    }
    timemachine.prototype.display=function(){
    var _this=this;
    (function(){
    //Use the innerHTML property to assign rich HTML to an element, in combo with closure- leak in IE!
    document.getElementById("numberdiv").innerHTML='<p><b>'+_this.offset+new Date().getSeconds()+'</b></p>'
    })();
    //Closure below, no leak by itself
    setTimeout(function(){_this.display()}, 1000)
    }
    var sample=new timemachine(5)
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  9. #9
    Join Date
    Aug 2004
    Posts
    10,143
    Thanks
    3
    Thanked 1,008 Times in 993 Posts
    Blog Entries
    16

    Default

    Thanks John, you've given me more to go by. Here are the important points surrounding my test:

    1) I'm using Drip (v0.5) to do the main testing. I should mention that the browser on my machine is IE7, though I'm pretty sure Drip either uses IE6, or some rigged up version of IE that's not the stock IE7.

    2) I gave your double closure example a quick run, though same result in Drip- that is, memory leaks still occur.

    3) To exaggerate the problem for testing purposes, I changed the setTimeout delay in my original code from 1000 to 100. Here are some screen captures:







    It's clear memory is being sucked up, at least in Drip, with the problem squarely on the rich HTML that's being assigned to the element not being discarded each time it's reset:

    Code:
    getElementById("numberdiv").innerHTML='<p><b>'+_this.offset+new Date().getSeconds()+'</b></p>'
    The more elements I add (P, B, DIV etc), the more leaks (not text nodes). I've tried using the DOM to dynamically remove the nodes one by one before reassigning new content to it using innerHTML (based on this article), though that didn't seem to do anything either. Something like:

    Code:
    while (getElementById("numberdiv").hasChildNodes())
    getElementById("numberdiv").removeNode(...)
    getElementById("numberdiv").innerHTML='<p><b>'+_this.offset+new Date().getSeconds()+'</b></p>'
    4) Regarding memory usage when the page is unloaded, nope, the memory isn't reclaimed, unless Drip is closed then relaunched.

    5) I agree too that Trey's idea of switching to using the DOM entirely, instead of .innerHTML, may very well fix the problem, but I'm as curious as I'm interested in finding a way to fix the problem when it comes to using .innerHTML in such a manner.

  10. #10
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    I really think that this a bug in Drip. I loaded your original code in IE 6 on a spare machine with taskmanager running and just let it go for several minutes. None of the memory indicators I mention before showed any leakage. I'll leave it up there for awhile. If I see any memory problems, I will come back to this thread to report them but, nothing so far.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •