目前正在开发一个基于JavaScript的动画项目。
我注意到,正确使用setInterval()
、setTimeout()
甚至requestAnimationFrame
都会在没有请求的情况下分配内存,并导致频繁的垃圾收集调用。更多GC调用=闪烁:-(
例如,当我在Google Chrome中调用init()来执行下面的简单代码时,内存分配+垃圾回收在最初的20-30秒内是可以接受的……
function init()
{
var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
return true
}
不知何故,在一分钟左右的时间内,分配的内存开始奇怪地增加!由于init()只调用一次,因此分配的内存大小增加的原因是什么?
(编辑:上传的chrome截图)
注意#1:是的,在下一个setInterval()之前,我已经尝试过调用clearInterval()。问题还是一样的!
注意#2:为了隔离问题,我将上面的代码保持简单和愚蠢。
发布于 2012-12-26 06:14:09
编辑:Yury's answer更好。
tl;dr IMO没有内存泄漏。正斜率仅仅是setInterval和setTimeout的效果。垃圾被收集,如锯齿模式所示,这意味着根据定义没有内存泄漏。(我想)。
我不确定是否有办法解决这个所谓的“内存泄漏”问题。在这种情况下,“内存泄漏”是指对setInterval函数的每次调用都会增加内存使用量,如内存分析器中的正斜率所示。
实际情况是没有实际的内存泄漏:垃圾收集器仍然能够收集内存。根据定义,内存泄漏“发生在计算机程序获取内存但未能将其释放回操作系统时。”
如下内存配置文件所示,没有发生内存泄漏。每次调用函数时,内存使用量都会增加。OP期望因为这是被反复调用的同一个函数,所以不应该增加内存。然而,事实并非如此。每次函数调用都会消耗内存。最终,垃圾被收集,创建锯齿模式。
我已经探索了几种重新排列间隔的方法,它们都会导致相同的锯齿模式(尽管有些尝试会导致垃圾收集,因为保留了引用)。
function doIt() {
console.log("hai")
}
function a() {
doIt();
setTimeout(b, 50);
}
function b() {
doIt();
setTimeout(a, 50);
}
a();
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/
function init()
{
var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
console.log('Hello');
}
init();
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/
显然,setTimeout
和setInterval
不是正式的Javascript的一部分(因此它们不是v8的一部分)。实现由实现者决定。我建议你看看the implementation of setInterval and such in node.js
发布于 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
发布于 2013-02-13 02:11:19
每次调用函数时,它都会创建一个stack frame。与许多其他语言不同,Javascript将堆栈帧存储在堆上,就像其他所有东西一样。这意味着每次调用一个函数时,都会向堆中添加一个新的堆栈帧。这一点加起来,最终会被垃圾回收。
考虑到Javascript的工作原理,这是不可避免的。唯一能做的就是让堆栈帧尽可能的小,我相信所有的实现都是这么做的。
https://stackoverflow.com/questions/14034107
复制相似问题