简体   繁体   中英

How does setTimeout() create a memory leak in this code?

I was reviewing the slides in this presentation: http://slid.es/gruizdevilla/memory

and on one of the slides, this code is presented with the suggestion that it creates a memory leak:

var buggyObject = {
   callAgain: function() {
     var ref = this;
     var val = setTimeout(function() {
        ref.callAgain();
     }, 1000);
   }
}

buggyObject.callAgain();
buggyObject = null;

Can someone explain the issue in more detail here? I might be missing some subtleties here.

This is definitely a memory leak. However, the memory consumption is so small and cannot be measured. I did some small changes to the source code.

  • I put the entire code inside a loop to create the same scenario 100,000 times
  • I increased the timer interval to about 16 minutes. This prevents browser from crashing

Here is the code:

for (var i = 0; i < 100000; i++) {
    var buggyObject = {
       callAgain: function() {
         var ref = this;
         var val = setTimeout(function() {
            ref.callAgain(); 
         }, 1000000); //16m
       }
    }

    buggyObject.callAgain();
    buggyObject = null;
}

Chrome 内存泄漏

My experiment:

I ran the code in Chrome Version 34.0.1847.116 m and captured memory changes using Developer Tools\\Timeline.

As we can see in the picture, around 32 MB of memory has been consumed for running this code and after a while it's been decreased to about 30 MB and stayed unchanged (see #1). After several garbage collecting attempts by Chrome (see #2) and one manual forced garbage collection by me (see #3, #4), the memory consumption remains unchanged. There is no more buggyObject and there is nothing we can do to release the memory. The only possible way is to close the browser.

What causes this?

The main reason for this behavior is the timer. Timer callback and its tied object, buggyObject will not be released until the timeout happens. In our case timer resets itself and runs forever and therefore its memory space will never be collected even if there is no reference to the original object.

There is another question that describes how setTimeout() looks like it has memory leaks, but in reality does not.

However, I think what the author is trying to say is that since buggyObject creates a setTimeout which calls itself, even if you change buggyObject to equal null (saying you are done with the object and it can be cleaned up), the object won't be garbage collected because there is still a reference to it in the setTimeout(). This is technically a memory leak because there is no longer any direct reference to the setTimeout function so that you could clear it later (kind of a zombie timeout if you will).

As advncd pointed out, the timer gets executed and adds even more data on the stack. There is a conceptual view of what happens:

var a = 123;
// call the setTimeout.function
  var a = 123;
  // call the setTimeout.function
    var a = 123;
    // call the setTimeout.function
      var a = 123;
      // call the setTimeout.function
        var a = 123;
        // call the setTimeout.function
          var a = 123;
          // call the setTimeout.function
            var a = 123;
            // call the setTimeout.function
              var a = 123;
              // call the setTimeout.function
                var a = 123;
                ...etc...

So each time a new variable a is allocated on the stack which grows forever.

What advncd did not mention, though, is the fact that you have a setInterval() function to do what you need to do: have the same function called over and over again. Now you still have a "memory leak" but only the initialization parameters leak (ie it won't grow each time the timer times out.)

So conceptually, the calls are flat and you avoid the leak:

a = 123;
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
...etc...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM