setTimeout() 递归调用 - 内存泄漏?

问题描述 投票:0回答:1

我正在实现长轮询系统的客户端。我读到的所有内容都表明,为了避免无限的堆栈深度,不要进行直接递归调用,而是使用

setTimeout()
间接调用,以便每次迭代都以干净的堆栈开始。

实现是:

function pollForEvents() {
    
    $.get(
        "GetEventLP", 
        null, 
        function(eventData) {
            console.log("Got event at "+new Date()+": "+JSON.stringify(eventData));
            setTimeout(function() {pollForEvents();}, 1); // Using setTimeout() avoids infinite recursion stack growth
            
        }).fail(function(xhr, status, err) {
            console.log("Long poll failed at "+new Date()+": "+util.getServerErrorText(xhr));
            // Wait before we try again to avoid fast failure polling
            setTimeout(function() { pollForEvents(); }, 60000);
        });
}

我让它运行一定次数的迭代,然后在

$.get()
调用处设置一个断点。在下一次迭代中,它会中断,Chrome 会显示与运行的迭代次数一样深的调用堆栈 - 例如它会无限地增长。我误解了什么吗?这看起来像是基于不断增加的调用堆栈大小的内存泄漏。

这是 Chrome 在 6 次迭代后显示的调用堆栈,请注意重复的

pollForEvents()
帧。

pollForEvents (index.js?v=1.02:406)
(anonymous) (index.js?v=1.02:411)
setTimeout (async)
(anonymous) (index.js?v=1.02:411)
i (jquery-3.1.1.min.js:2)
fireWith (jquery-3.1.1.min.js:2)
A (jquery-3.1.1.min.js:4)
(anonymous) (jquery-3.1.1.min.js:4)
load (async)
send (jquery-3.1.1.min.js:4)
ajax (jquery-3.1.1.min.js:4)
r.<computed> (jquery-3.1.1.min.js:4)
pollForEvents (index.js?v=1.02:406)
(anonymous) (index.js?v=1.02:411)
setTimeout (async)
(anonymous) (index.js?v=1.02:411)
i (jquery-3.1.1.min.js:2)
fireWith (jquery-3.1.1.min.js:2)
A (jquery-3.1.1.min.js:4)
(anonymous) (jquery-3.1.1.min.js:4)
load (async)
send (jquery-3.1.1.min.js:4)
ajax (jquery-3.1.1.min.js:4)
r.<computed> (jquery-3.1.1.min.js:4)
pollForEvents (index.js?v=1.02:406)
(anonymous) (index.js?v=1.02:411)
setTimeout (async)
(anonymous) (index.js?v=1.02:411)
i (jquery-3.1.1.min.js:2)
fireWith (jquery-3.1.1.min.js:2)
A (jquery-3.1.1.min.js:4)
(anonymous) (jquery-3.1.1.min.js:4)
load (async)
send (jquery-3.1.1.min.js:4)
ajax (jquery-3.1.1.min.js:4)
r.<computed> (jquery-3.1.1.min.js:4)
pollForEvents (index.js?v=1.02:406)
(anonymous) (index.js?v=1.02:411)
setTimeout (async)
(anonymous) (index.js?v=1.02:411)
i (jquery-3.1.1.min.js:2)
fireWith (jquery-3.1.1.min.js:2)
A (jquery-3.1.1.min.js:4)
(anonymous) (jquery-3.1.1.min.js:4)
load (async)
send (jquery-3.1.1.min.js:4)
ajax (jquery-3.1.1.min.js:4)
r.<computed> (jquery-3.1.1.min.js:4)
pollForEvents (index.js?v=1.02:406)
(anonymous) (index.js?v=1.02:411)
setTimeout (async)
(anonymous) (index.js?v=1.02:411)
i (jquery-3.1.1.min.js:2)
fireWith (jquery-3.1.1.min.js:2)
A (jquery-3.1.1.min.js:4)
(anonymous) (jquery-3.1.1.min.js:4)
load (async)
send (jquery-3.1.1.min.js:4)
ajax (jquery-3.1.1.min.js:4)
r.<computed> (jquery-3.1.1.min.js:4)
pollForEvents (index.js?v=1.02:406)
(anonymous) (index.js?v=1.02:411)
setTimeout (async)
(anonymous) (index.js?v=1.02:411)
i (jquery-3.1.1.min.js:2)
fireWith (jquery-3.1.1.min.js:2)
A (jquery-3.1.1.min.js:4)
(anonymous) (jquery-3.1.1.min.js:4)
javascript recursion memory-leaks
1个回答
2
投票

我发现这里发生了什么,如果其他人开始对像这样的明显的调用堆栈内存泄漏感到恐慌,也许这很有用。这不是内存泄漏,但原因如下:

默认的 Chrome 开发人员调用堆栈视图启用了“异步堆栈跟踪”,这似乎在涉及异步函数时创建了堆栈的人工视图(https://developer.chrome.com/docs/devtools/javascript/reference /#调用堆栈)。它实际上是过去调用堆栈的视图,它不仅仅显示当前堆栈。

启用此功能后,调试器将保留先前的异步调用堆栈并在此视图中显示所有内容。堆栈之间画有一条细线,但这意味着什么并不明显。此视图对于调试异步调用链非常方便,但如果您认为正在查看一组非常深的嵌套调用,则可能具有欺骗性。禁用此功能后,堆栈仅包含预期的一组帧 - 没有调用堆栈内存泄漏。

© www.soinside.com 2019 - 2024. All rights reserved.