首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >JavaScript setInterval()方法会导致内存泄漏吗?

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

Stack Overflow用户
提问于 2012-12-26 05:27:11
回答 8查看 47.2K关注 0票数 68

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

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

例如,当我在Google Chrome中调用init()来执行下面的简单代码时,内存分配+垃圾回收在最初的20-30秒内是可以接受的……

代码语言:javascript
复制
function init()
{
    var ref = window.setInterval(function() { draw(); }, 50);
}

function draw()
{
    return true
}

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

(编辑:上传的chrome截图)

注意#1:是的,在下一个setInterval()之前,我已经尝试过调用clearInterval()。问题还是一样的!

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

EN

回答 8

Stack Overflow用户

发布于 2012-12-26 06:14:09

编辑:Yury's answer更好。

tl;dr IMO没有内存泄漏。正斜率仅仅是setInterval和setTimeout的效果。垃圾被收集,如锯齿模式所示,这意味着根据定义没有内存泄漏。(我想)。

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

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

如下内存配置文件所示,没有发生内存泄漏。每次调用函数时,内存使用量都会增加。OP期望因为这是被反复调用的同一个函数,所以不应该增加内存。然而,事实并非如此。每次函数调用都会消耗内存。最终,垃圾被收集,创建锯齿模式。

我已经探索了几种重新排列间隔的方法,它们都会导致相同的锯齿模式(尽管有些尝试会导致垃圾收集,因为保留了引用)。

代码语言:javascript
复制
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
复制
function b() {
    var a = setInterval(function() {
        console.log("Hello");
        clearInterval(a);
        b();                
    }, 50);
}
b();

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

代码语言:javascript
复制
function init()
{
    var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
    console.log('Hello');
}
init();

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

代码语言:javascript
复制
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/

显然,setTimeoutsetInterval不是正式的Javascript的一部分(因此它们不是v8的一部分)。实现由实现者决定。我建议你看看the implementation of setInterval and such in node.js

票数 54
EN

Stack Overflow用户

发布于 2013-02-13 18:34:06

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

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

票数 30
EN

Stack Overflow用户

发布于 2013-02-13 02:11:19

每次调用函数时,它都会创建一个stack frame。与许多其他语言不同,Javascript将堆栈帧存储在堆上,就像其他所有东西一样。这意味着每次调用一个函数时,都会向堆中添加一个新的堆栈帧。这一点加起来,最终会被垃圾回收。

考虑到Javascript的工作原理,这是不可避免的。唯一能做的就是让堆栈帧尽可能的小,我相信所有的实现都是这么做的。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14034107

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档