JavaScript setInterval()方法会导致内存泄漏吗?

时间:2022-01-08 08:59:43

Currently developing a JavaScript based animation project.

目前正在开发一个基于JavaScript的动画项目。

I have noticed that, proper use of setInterval(), setTimeout() and even requestAnimationFrame allocates memory without my request, and causes frequent garbage collection calls. More GC calls = flickers :-(

我注意到,正确地使用setInterval()、setTimeout()甚至requestAnimationFrame在没有请求的情况下分配内存,会导致频繁的垃圾收集调用。更多GC调用=闪烁:-(

For instance; when I execute the following simple code by calling init() in Google Chrome, memory allocation + garbage collection is fine for the first 20-30 seconds...

例如;当我在谷歌Chrome中调用init()执行以下简单代码时,内存分配+垃圾收集在最初20-30秒内都没问题……

function init()
{
    var ref = window.setInterval(function() { draw(); }, 50);
}

function draw()
{
    return true
}

Somehow, within a minute or so, starts a strange increase in allocated memory! Since init() is called only for once, what is the reason for the increase in allocated memory size?

不知何故,在一分钟左右,开始了一个奇怪的增加分配内存!由于init()只调用一次,那么增加分配内存大小的原因是什么?

(Edit: chrome screenshot uploaded)

(编辑:chrome截图上传)

JavaScript setInterval()方法会导致内存泄漏吗?

NOTE #1: Yes, I have tried calling clearInterval() before the next setInterval(). Problem remains the same!

注意#1:是的,我试过在下一个setInterval()之前调用clearInterval()。问题是相同的!

NOTE #2: In order to isolate the problem, I'm keeping the above code simple and stupid.

注意#2:为了隔离问题,我将上面的代码保持简单和愚蠢。

8 个解决方案

#1


49  

EDIT: Yury's answer is better.

编辑:尤里的回答更好。


tl;dr IMO there is no memory leak. The positive slope is simply the effect of setInterval and setTimeout. The garbage is collected, as seen by sawtooth patterns, meaning by definition there is no memory leak. (I think).

在我看来没有内存泄漏。正斜率仅仅是setInterval和setTimeout的影响。通过锯齿模式可以看到,垃圾被收集,这意味着从定义上说,没有内存泄漏。(我认为)。

I'm not sure there is a way to work around this so-called "memory leak." In this case, "memory leak" is referring to each call to the setInterval function increasing the memory usage, as seen by the positive slopes in the memory profiler.

我不确定是否有办法解决所谓的“内存泄漏”。在这种情况下,“内存泄漏”指的是每个对setInterval函数的调用都增加了内存的使用,如内存分析器中的正斜率所示。

The reality is that there is no actual memory leak: the garbage collector is still able to collect the memory. Memory leak by definition "occurs when a computer program acquires memory but fails to release it back to the operating system."

实际情况是没有实际的内存泄漏:垃圾收集器仍然能够收集内存。根据定义,内存泄漏“发生在计算机程序获得内存但未能将其释放回操作系统时。”

As shown by the memory profiles below, memory leak is not occurring. The memory usage is increasing with each function call. The OP expects that because this is the same function being called over and over, there should be no memory increase. However, this is not the case. Memory is consumed with each function call. Eventually, the garbage is collected, creating the sawtooth pattern.

如下面的内存概要所示,内存泄漏不会发生。每个函数调用都会增加内存使用量。OP期望由于这是反复调用的同一个函数,因此不应该增加内存。然而,事实并非如此。每个函数调用都会消耗内存。最终,垃圾被收集起来,形成锯齿状。

I've explored several ways of rearranging the intervals, and they all lead to the same sawtooth pattern (although some attempts lead to garbage collection never happening as references were retained).

我已经探索了一些重新安排时间间隔的方法,它们都导致了相同的锯齿模式(尽管一些尝试导致垃圾收集从来没有发生,因为引用被保留)。

function doIt() {
    console.log("hai")
}

function a() {
    doIt();
    setTimeout(b, 50);
}
function b() {
    doIt();
    setTimeout(a, 50);
}

a();

http://fiddle.jshell.net/QNRSK/14/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/14/

function b() {
    var a = setInterval(function() {
        console.log("Hello");
        clearInterval(a);
        b();                
    }, 50);
}
b();

http://fiddle.jshell.net/QNRSK/17/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/17/

function init()
{
    var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
    console.log('Hello');
}
init();

http://fiddle.jshell.net/QNRSK/20/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/20/

function init()
{
    window.ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
    console.log('Hello');
    clearInterval(window.ref);
    init();
}
init();​

http://fiddle.jshell.net/QNRSK/21/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/21/

Apparently setTimeout and setInterval are not officially parts of Javascript (hence they are not a part of v8). The implementation is left up to the implementer. I suggest you take a look at the implementation of setInterval and such in node.js

显然,setTimeout和setInterval不是Javascript的官方部分(因此它们不是v8的一部分)。实现由实现者决定。我建议您看看setInterval的实现以及node.js中的实现。

#2


25  

The problem here is not in the code itself, it doesn't leak. It is because of the way Timeline panel is implemented. When Timeline records events we collect JavaScript stack traces on each invocation of setInterval callback. The stack trace is first allocated in JS heap and then copied into native data structures, after the stack trace is copied into the native event it becomes garbage in the JS heap. This is reflected on the graph. Disabling the following call http://trac.webkit.org/browser/trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp#L55 makes the memory graph flat.

这里的问题不在代码本身,它不会泄漏。这是因为时间轴面板的实现方式。当时间轴记录事件时,我们在每次调用setInterval回调时收集JavaScript堆栈跟踪。堆栈跟踪首先在JS堆中分配,然后复制到本机数据结构中,在堆栈跟踪被复制到本机事件之后,它就成为JS堆中的垃圾。这反映在图表上。禁用以下调用http://trac.webkit.org/browser/trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp#L55将使内存图变得扁平。

There is a bug related to this issue: https://code.google.com/p/chromium/issues/detail?id=120186

有一个与这个问题相关的bug: https://code.google.com/p/chromium/issues/detail?id=120186

#3


11  

Each time you make a function call, it creates a stack frame. Unlike lots of other languages, Javascript stores the stack frame on the heap, just like everything else. This means that every time you call a function, which you're doing every 50ms, a new stack frame is being added to the heap. This adds up and is eventually garbage collected.

每次进行函数调用时,它都会创建一个堆栈框架。与许多其他语言不同,Javascript将堆栈框架存储在堆上,就像其他语言一样。这意味着每次调用一个函数时,每50毫秒,一个新的堆栈帧就被添加到堆中。加起来就是垃圾收集。

It's kinda unavoidable, given how Javascript works. The only thing that can really be done to mitigate it is make the stack frames as small as possible, which I'm sure all the implementations do.

考虑到Javascript的工作方式,这是不可避免的。唯一可以做的事情就是使堆栈帧尽可能小,我相信所有的实现都会这么做。

#4


6  

I wanted to respond to your comment about setInterval and flickering:

我想回答你关于setInterval和flickering的评论:

I have noticed that, proper use of setInterval(), setTimeout() and even requestAnimationFrame allocates memory without my request, and causes frequent garbage collection calls. More GC calls = flickers :-(

我注意到,正确地使用setInterval()、setTimeout()甚至requestAnimationFrame在没有请求的情况下分配内存,会导致频繁的垃圾收集调用。更多GC调用=闪烁:-(

You might want to try replacing the setInterval call with a less evil self-invoking function based on setTimeout. Paul Irish mentions this in the talk called 10 things I learned from the jQuery source (video here, notes here see #2). What you do is replace your call to setInterval with a function that invokes itself indirectly through setTimeout after it completes the work it's supposed to do. To quote the talk:

您可能想尝试使用基于setTimeout的不那么邪恶的自调用函数来替换setInterval调用。Paul Irish在《从jQuery源代码中学到的10件事》(视频在这里,注释在这里见#2)中提到了这一点。您要做的是用一个函数替换对setInterval的调用,该函数在它完成预期的工作之后通过setTimeout间接地调用自己。引用的讨论:

Many have argued that setInterval is an evil function. It keeps calling a function at specified intervals regardless of whether the function is finished or not.

许多人认为setInterval是一个有害的函数。无论函数是否完成,它都以指定的间隔调用函数。

Using your example code above, you could update your init function from:

使用上面的示例代码,您可以从:

function init() 
{
    var ref = window.setInterval(function() { draw(); }, 50);
}

to:

:

function init()
{
     //init stuff

     //awesome code

     //start rendering
     drawLoop();
}

function drawLoop()
{
   //do work
   draw();

   //queue more work
   setTimeout(drawLoop, 50);
}

This should help a bit because:

这应该会有所帮助,因为:

  1. draw() won't be called again by your rendering loop until it's completed
  2. 绘制()在绘制循环完成之前不会被再次调用
  3. as many of the above answers point out, all of the uninterrupted function calls from setInterval do put overhead on the browser.
  4. 正如上面的许多答案所指出的,来自setInterval的所有不间断函数调用都会给浏览器带来开销。
  5. debugging is a bit easier as you're not interrupted by the continued firing of setInterval
  6. 调试更容易一些,因为您不会被持续的setInterval触发而中断

Hope this helps!

希望这可以帮助!

#5


3  

Chrome is hardly seeing any memory pressure from your program (1.23 MB is very low memory usage by today's standards), so it probably does not think it needs to GC aggressively. If you modify your program to use more memory, you will see the garbage collector kick in. e.g. try this:

Chrome几乎看不到来自程序的内存压力(1.23 MB是当今标准的非常低的内存使用量),因此它可能认为不需要积极地使用GC。如果您修改您的程序以使用更多的内存,您将看到垃圾收集器介入。例如:试试这个:

<!html>
<html>
<head>
<title>Where goes memory?</title>
</head>
<body>

Greetings!

<script>
function init()
{
    var ref = window.setInterval(function() { draw(); }, 50);
}

function draw()
{
    var ar = new Array();
    for (var i = 0; i < 1e6; ++i) {
        ar.push(Math.rand());
    }
    return true
}

init();
</script>

</body>
</html>

When I run this, I get a saw tooth memory usage pattern, peaking bellow around 13.5MB (again, pretty small by today's standards).

当我运行这个程序时,我得到了一个锯齿内存使用模式,它的峰值在13.5MB左右(同样,以今天的标准来看,非常小)。

PS: Specifics of my browsers:

附注:我的浏览器细节:

Google Chrome   23.0.1271.101 (Official Build 172594)
OS  Mac OS X
WebKit  537.11 (@136278)
JavaScript  V8 3.13.7.5
Flash   11.5.31.5
User Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.101 Safari/537.11

#6


3  

Try doing this without the anonymous function. For example:

尝试在没有匿名函数的情况下执行这个操作。例如:

function draw()
{
    return true;
}

function init()
{
    var ref = window.setInterval(draw, 50);
}

Does it still behave the same way?

它的行为是否仍然相同?

#7


2  

There does not appear to be a memory leak. So long as the memory usage decreases again after GC, and the overall memory usage does not trend upward on average, there is no leak.

似乎没有内存泄漏。只要GC之后的内存使用再次减少,并且总体内存使用平均没有上升趋势,就不会出现泄漏。

The "real" question I'm seeing here is that setInterval does indeed use memory to operate, and it doesn't look like it should be allocating anything. In reality it needs to allocate a few things:

我在这里看到的“真正的”问题是setInterval确实使用内存来操作,而且看起来它不应该分配任何东西。实际上,它需要分配一些东西:

  1. It will need to allocate some stack space to execute both the anonymous function and the draw() routine.
  2. 它需要分配一些堆栈空间来执行匿名函数和draw()例程。
  3. I don't know if needs to allocate any temporary data to perform the calls themselves (probably not)
  4. 我不知道是否需要分配任何临时数据来执行调用本身(可能不需要)
  5. It needs to allocate a small amount of storage to hold that true return value from draw().
  6. 它需要分配少量的存储空间来保存draw()的真实返回值。
  7. Internally, setInterval may allocate additional memory to re-schedule a reoccurring event (I don't know how it works internally, it may re-use the existing record).
  8. 在内部,setInterval可以分配额外的内存来重新安排一个重新发生的事件(我不知道它在内部是如何工作的,它可能会重新使用现有的记录)。
  9. The JIT may try to trace that method, which would allocate additional storage for the trace and some metrics. The VM may determine this method is too small to trace it, I don't know exactly what all the thresholds are for turning tracing on or off. If you run this code long enough for the VM to identify it as "hot", it may allocate even more memory to hold the JIT compiled machine code (after which, I would expect average memory usage to decrease, because the generated machine code should allocate less memory in most cases)
  10. JIT可能尝试跟踪该方法,该方法将为跟踪和一些度量分配额外的存储。VM可能决定这种方法太小,不能跟踪它,我不知道所有的阈值把跟踪打开或关闭。如果你足够VM运行此代码识别为“热”,它可能会分配更多的内存来保存JIT编译的机器代码(这后,我期望平均内存使用减少,因为生成机器代码分配更少的内存应该在大多数情况下)

Every time your anonymous function executes there is going to be some memory allocated. When those allocations add up to some threshold, the GC will kick in and clean up to bring you back down to a base level. The cycle will continue like this until you shut it off. This is expected behavior.

每次执行匿名函数时都会分配一些内存。当这些分配累加到某个阈值时,GC将启动并清理,使您回到基本级别。循环将继续这样,直到你关闭它。这是预期的行为。

#8


1  

I also have the same problem. The client reported me that the memory of its computer was increasing every time more and more. At first I thought it was really strange that a web app could make that even though it was accessed by a simple browser. I noticed that this happened only in Chrome.

我也有同样的问题。客户向我报告说,它的电脑内存越来越大。一开始我觉得很奇怪的是,一个web应用程序能够做到这一点,即使它是由一个简单的浏览器访问的。我注意到这只发生在Chrome上。

However, I started with a partner to investigate and through the developer tools of Chrome and the manager task we could see the memory increase the client had reported me.

然而,我开始与一个合作伙伴进行调查,通过Chrome的开发工具和manager任务,我们可以看到客户报告给我的内存增加。

Then we see that a jquery function (request animation frame) was loaded over and over increasing the system memory. After that, we saw thanks to this post, a jquery countdown was doing that, because it has inside a "SETINTERVAL" that each time was updating the date in my app's layout.

然后,我们看到jquery函数(请求动画帧)被反复加载,以增加系统内存。在那之后,我们看到了感谢这篇文章,jquery倒计时就这么做了,因为它有一个“SETINTERVAL”,每次在我的应用程序布局中更新日期。

As I am working with ASP.NET MVC, I just quit this jquery script countdown from the BundleConfig, and from my layout, replacing my time countdown with the following code:

因为我在使用ASP。NET MVC,我从BundleConfig退出了这个jquery脚本倒计时,从我的布局中,用下面的代码替换我的时间倒计时:

@(DateTime.Now.ToString("dd/MM/yyyy HH:mm"))

#1


49  

EDIT: Yury's answer is better.

编辑:尤里的回答更好。


tl;dr IMO there is no memory leak. The positive slope is simply the effect of setInterval and setTimeout. The garbage is collected, as seen by sawtooth patterns, meaning by definition there is no memory leak. (I think).

在我看来没有内存泄漏。正斜率仅仅是setInterval和setTimeout的影响。通过锯齿模式可以看到,垃圾被收集,这意味着从定义上说,没有内存泄漏。(我认为)。

I'm not sure there is a way to work around this so-called "memory leak." In this case, "memory leak" is referring to each call to the setInterval function increasing the memory usage, as seen by the positive slopes in the memory profiler.

我不确定是否有办法解决所谓的“内存泄漏”。在这种情况下,“内存泄漏”指的是每个对setInterval函数的调用都增加了内存的使用,如内存分析器中的正斜率所示。

The reality is that there is no actual memory leak: the garbage collector is still able to collect the memory. Memory leak by definition "occurs when a computer program acquires memory but fails to release it back to the operating system."

实际情况是没有实际的内存泄漏:垃圾收集器仍然能够收集内存。根据定义,内存泄漏“发生在计算机程序获得内存但未能将其释放回操作系统时。”

As shown by the memory profiles below, memory leak is not occurring. The memory usage is increasing with each function call. The OP expects that because this is the same function being called over and over, there should be no memory increase. However, this is not the case. Memory is consumed with each function call. Eventually, the garbage is collected, creating the sawtooth pattern.

如下面的内存概要所示,内存泄漏不会发生。每个函数调用都会增加内存使用量。OP期望由于这是反复调用的同一个函数,因此不应该增加内存。然而,事实并非如此。每个函数调用都会消耗内存。最终,垃圾被收集起来,形成锯齿状。

I've explored several ways of rearranging the intervals, and they all lead to the same sawtooth pattern (although some attempts lead to garbage collection never happening as references were retained).

我已经探索了一些重新安排时间间隔的方法,它们都导致了相同的锯齿模式(尽管一些尝试导致垃圾收集从来没有发生,因为引用被保留)。

function doIt() {
    console.log("hai")
}

function a() {
    doIt();
    setTimeout(b, 50);
}
function b() {
    doIt();
    setTimeout(a, 50);
}

a();

http://fiddle.jshell.net/QNRSK/14/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/14/

function b() {
    var a = setInterval(function() {
        console.log("Hello");
        clearInterval(a);
        b();                
    }, 50);
}
b();

http://fiddle.jshell.net/QNRSK/17/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/17/

function init()
{
    var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
    console.log('Hello');
}
init();

http://fiddle.jshell.net/QNRSK/20/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/20/

function init()
{
    window.ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
    console.log('Hello');
    clearInterval(window.ref);
    init();
}
init();​

http://fiddle.jshell.net/QNRSK/21/ JavaScript setInterval()方法会导致内存泄漏吗?

http://fiddle.jshell.net/QNRSK/21/

Apparently setTimeout and setInterval are not officially parts of Javascript (hence they are not a part of v8). The implementation is left up to the implementer. I suggest you take a look at the implementation of setInterval and such in node.js

显然,setTimeout和setInterval不是Javascript的官方部分(因此它们不是v8的一部分)。实现由实现者决定。我建议您看看setInterval的实现以及node.js中的实现。

#2


25  

The problem here is not in the code itself, it doesn't leak. It is because of the way Timeline panel is implemented. When Timeline records events we collect JavaScript stack traces on each invocation of setInterval callback. The stack trace is first allocated in JS heap and then copied into native data structures, after the stack trace is copied into the native event it becomes garbage in the JS heap. This is reflected on the graph. Disabling the following call http://trac.webkit.org/browser/trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp#L55 makes the memory graph flat.

这里的问题不在代码本身,它不会泄漏。这是因为时间轴面板的实现方式。当时间轴记录事件时,我们在每次调用setInterval回调时收集JavaScript堆栈跟踪。堆栈跟踪首先在JS堆中分配,然后复制到本机数据结构中,在堆栈跟踪被复制到本机事件之后,它就成为JS堆中的垃圾。这反映在图表上。禁用以下调用http://trac.webkit.org/browser/trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp#L55将使内存图变得扁平。

There is a bug related to this issue: https://code.google.com/p/chromium/issues/detail?id=120186

有一个与这个问题相关的bug: https://code.google.com/p/chromium/issues/detail?id=120186

#3


11  

Each time you make a function call, it creates a stack frame. Unlike lots of other languages, Javascript stores the stack frame on the heap, just like everything else. This means that every time you call a function, which you're doing every 50ms, a new stack frame is being added to the heap. This adds up and is eventually garbage collected.

每次进行函数调用时,它都会创建一个堆栈框架。与许多其他语言不同,Javascript将堆栈框架存储在堆上,就像其他语言一样。这意味着每次调用一个函数时,每50毫秒,一个新的堆栈帧就被添加到堆中。加起来就是垃圾收集。

It's kinda unavoidable, given how Javascript works. The only thing that can really be done to mitigate it is make the stack frames as small as possible, which I'm sure all the implementations do.

考虑到Javascript的工作方式,这是不可避免的。唯一可以做的事情就是使堆栈帧尽可能小,我相信所有的实现都会这么做。

#4


6  

I wanted to respond to your comment about setInterval and flickering:

我想回答你关于setInterval和flickering的评论:

I have noticed that, proper use of setInterval(), setTimeout() and even requestAnimationFrame allocates memory without my request, and causes frequent garbage collection calls. More GC calls = flickers :-(

我注意到,正确地使用setInterval()、setTimeout()甚至requestAnimationFrame在没有请求的情况下分配内存,会导致频繁的垃圾收集调用。更多GC调用=闪烁:-(

You might want to try replacing the setInterval call with a less evil self-invoking function based on setTimeout. Paul Irish mentions this in the talk called 10 things I learned from the jQuery source (video here, notes here see #2). What you do is replace your call to setInterval with a function that invokes itself indirectly through setTimeout after it completes the work it's supposed to do. To quote the talk:

您可能想尝试使用基于setTimeout的不那么邪恶的自调用函数来替换setInterval调用。Paul Irish在《从jQuery源代码中学到的10件事》(视频在这里,注释在这里见#2)中提到了这一点。您要做的是用一个函数替换对setInterval的调用,该函数在它完成预期的工作之后通过setTimeout间接地调用自己。引用的讨论:

Many have argued that setInterval is an evil function. It keeps calling a function at specified intervals regardless of whether the function is finished or not.

许多人认为setInterval是一个有害的函数。无论函数是否完成,它都以指定的间隔调用函数。

Using your example code above, you could update your init function from:

使用上面的示例代码,您可以从:

function init() 
{
    var ref = window.setInterval(function() { draw(); }, 50);
}

to:

:

function init()
{
     //init stuff

     //awesome code

     //start rendering
     drawLoop();
}

function drawLoop()
{
   //do work
   draw();

   //queue more work
   setTimeout(drawLoop, 50);
}

This should help a bit because:

这应该会有所帮助,因为:

  1. draw() won't be called again by your rendering loop until it's completed
  2. 绘制()在绘制循环完成之前不会被再次调用
  3. as many of the above answers point out, all of the uninterrupted function calls from setInterval do put overhead on the browser.
  4. 正如上面的许多答案所指出的,来自setInterval的所有不间断函数调用都会给浏览器带来开销。
  5. debugging is a bit easier as you're not interrupted by the continued firing of setInterval
  6. 调试更容易一些,因为您不会被持续的setInterval触发而中断

Hope this helps!

希望这可以帮助!

#5


3  

Chrome is hardly seeing any memory pressure from your program (1.23 MB is very low memory usage by today's standards), so it probably does not think it needs to GC aggressively. If you modify your program to use more memory, you will see the garbage collector kick in. e.g. try this:

Chrome几乎看不到来自程序的内存压力(1.23 MB是当今标准的非常低的内存使用量),因此它可能认为不需要积极地使用GC。如果您修改您的程序以使用更多的内存,您将看到垃圾收集器介入。例如:试试这个:

<!html>
<html>
<head>
<title>Where goes memory?</title>
</head>
<body>

Greetings!

<script>
function init()
{
    var ref = window.setInterval(function() { draw(); }, 50);
}

function draw()
{
    var ar = new Array();
    for (var i = 0; i < 1e6; ++i) {
        ar.push(Math.rand());
    }
    return true
}

init();
</script>

</body>
</html>

When I run this, I get a saw tooth memory usage pattern, peaking bellow around 13.5MB (again, pretty small by today's standards).

当我运行这个程序时,我得到了一个锯齿内存使用模式,它的峰值在13.5MB左右(同样,以今天的标准来看,非常小)。

PS: Specifics of my browsers:

附注:我的浏览器细节:

Google Chrome   23.0.1271.101 (Official Build 172594)
OS  Mac OS X
WebKit  537.11 (@136278)
JavaScript  V8 3.13.7.5
Flash   11.5.31.5
User Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.101 Safari/537.11

#6


3  

Try doing this without the anonymous function. For example:

尝试在没有匿名函数的情况下执行这个操作。例如:

function draw()
{
    return true;
}

function init()
{
    var ref = window.setInterval(draw, 50);
}

Does it still behave the same way?

它的行为是否仍然相同?

#7


2  

There does not appear to be a memory leak. So long as the memory usage decreases again after GC, and the overall memory usage does not trend upward on average, there is no leak.

似乎没有内存泄漏。只要GC之后的内存使用再次减少,并且总体内存使用平均没有上升趋势,就不会出现泄漏。

The "real" question I'm seeing here is that setInterval does indeed use memory to operate, and it doesn't look like it should be allocating anything. In reality it needs to allocate a few things:

我在这里看到的“真正的”问题是setInterval确实使用内存来操作,而且看起来它不应该分配任何东西。实际上,它需要分配一些东西:

  1. It will need to allocate some stack space to execute both the anonymous function and the draw() routine.
  2. 它需要分配一些堆栈空间来执行匿名函数和draw()例程。
  3. I don't know if needs to allocate any temporary data to perform the calls themselves (probably not)
  4. 我不知道是否需要分配任何临时数据来执行调用本身(可能不需要)
  5. It needs to allocate a small amount of storage to hold that true return value from draw().
  6. 它需要分配少量的存储空间来保存draw()的真实返回值。
  7. Internally, setInterval may allocate additional memory to re-schedule a reoccurring event (I don't know how it works internally, it may re-use the existing record).
  8. 在内部,setInterval可以分配额外的内存来重新安排一个重新发生的事件(我不知道它在内部是如何工作的,它可能会重新使用现有的记录)。
  9. The JIT may try to trace that method, which would allocate additional storage for the trace and some metrics. The VM may determine this method is too small to trace it, I don't know exactly what all the thresholds are for turning tracing on or off. If you run this code long enough for the VM to identify it as "hot", it may allocate even more memory to hold the JIT compiled machine code (after which, I would expect average memory usage to decrease, because the generated machine code should allocate less memory in most cases)
  10. JIT可能尝试跟踪该方法,该方法将为跟踪和一些度量分配额外的存储。VM可能决定这种方法太小,不能跟踪它,我不知道所有的阈值把跟踪打开或关闭。如果你足够VM运行此代码识别为“热”,它可能会分配更多的内存来保存JIT编译的机器代码(这后,我期望平均内存使用减少,因为生成机器代码分配更少的内存应该在大多数情况下)

Every time your anonymous function executes there is going to be some memory allocated. When those allocations add up to some threshold, the GC will kick in and clean up to bring you back down to a base level. The cycle will continue like this until you shut it off. This is expected behavior.

每次执行匿名函数时都会分配一些内存。当这些分配累加到某个阈值时,GC将启动并清理,使您回到基本级别。循环将继续这样,直到你关闭它。这是预期的行为。

#8


1  

I also have the same problem. The client reported me that the memory of its computer was increasing every time more and more. At first I thought it was really strange that a web app could make that even though it was accessed by a simple browser. I noticed that this happened only in Chrome.

我也有同样的问题。客户向我报告说,它的电脑内存越来越大。一开始我觉得很奇怪的是,一个web应用程序能够做到这一点,即使它是由一个简单的浏览器访问的。我注意到这只发生在Chrome上。

However, I started with a partner to investigate and through the developer tools of Chrome and the manager task we could see the memory increase the client had reported me.

然而,我开始与一个合作伙伴进行调查,通过Chrome的开发工具和manager任务,我们可以看到客户报告给我的内存增加。

Then we see that a jquery function (request animation frame) was loaded over and over increasing the system memory. After that, we saw thanks to this post, a jquery countdown was doing that, because it has inside a "SETINTERVAL" that each time was updating the date in my app's layout.

然后,我们看到jquery函数(请求动画帧)被反复加载,以增加系统内存。在那之后,我们看到了感谢这篇文章,jquery倒计时就这么做了,因为它有一个“SETINTERVAL”,每次在我的应用程序布局中更新日期。

As I am working with ASP.NET MVC, I just quit this jquery script countdown from the BundleConfig, and from my layout, replacing my time countdown with the following code:

因为我在使用ASP。NET MVC,我从BundleConfig退出了这个jquery脚本倒计时,从我的布局中,用下面的代码替换我的时间倒计时:

@(DateTime.Now.ToString("dd/MM/yyyy HH:mm"))