JavaScript内存泄漏

7
我注意到我刚写的一些JavaScript似乎存在内存泄漏问题,这是一个相当简单的代码块 - 多亏了jQuery - 但我可以在任务管理器中观察它运行,内存使用量会缓慢地增加4到40个字节。
我所做的就是通过getJSON将一些数据传递给ASP MVC控制器/操作:
$(document).ready(function () {
    var olddata = "";
    window.setInterval(function () {
        var options = JSON.stringify({
            orderby: "name"
        });
        var params = {
            options: options,
            data: olddata ? JSON.stringify(olddata) : ""
        };
        $.getJSON("/Home/GetTasks", params, function (json) {
            olddata = json;
            json = null;
        });
        params = null;
        options = null;
    }, 1000);
});

我已经将计时器的值增加了,以便更容易地查看问题。显然我在这里做错了什么,但是看不出来。

我应该清理getJSON调用吗?

TIA。


我目前正在进行类似的测试。我有一个简单的HTML页面,通过XHR调用另一个HTML页面。它不进行任何其他处理、DOM操作或任何脚本编写。我发现进行XHR调用确实会导致内存泄漏。Chrome泄漏非常少,IE泄漏较少,而FF则会大量泄漏。总之,在浏览器中执行Ajax将会导致内存占用略微增加。 - Mrchief
1
你可以在这里改进的一件事是将内联函数从 setInterval 中移出。定义它,然后在 setInterval 中使用其处理程序。这将有助于在一定程度上减轻泄漏问题。 - Mrchief
每次间隔触发时,您也可以停止重新定义参数和选项。 - sciritai
你每次请求返回的JSON大小是否大约为4到40字节的内存增量? - Endophage
@Mrchief和sciritai - 你们指出的这两个问题都不应该导致泄漏。应该使用局部变量,并在函数完成时释放它,以及任何保留它作为持久闭包的东西。如果所有局部变量都在$(document).ready()范围内(因此只有一个副本),则会更少地依赖浏览器垃圾回收,但如果setInterval时间小于getJSON响应时间,从而同时存在两个getJSON调用,则可能会创建问题。 - jfriend00
1个回答

6

如何确定内存泄漏?

在4字节和40字节这样的小数字范围内,你可能只是看到堆增长,但堆中的一些新块是“空闲”的,可供将来使用,因此虽然整个应用程序的内存使用量增加了,但内存实际上并没有泄漏,并且将来会可用,因此不会永远增长。

如果这是你的实验的全部范围,那么我认为代码没有任何问题。

这里有三个函数闭包。$(document).ready()闭包持续了你的代码生命周期,但它只是一次性的,所以不应该有任何问题。

传递给setInterval()的匿名函数使得$(document).ready()闭包一直存在。每次调用setInterval()匿名函数时,都会获得一个新的局部变量集,并在先前的调用运行完成时释放旧的局部变量集。

传递给getJSON()的匿名函数在setInterval匿名函数上创建了一个闭包,但该闭包应该只持续到getJSON函数完成时,当它完成时,setInterval()匿名函数闭包应该被释放。

我看到唯一持续的闭包是$(document).ready()闭包,这是你想要的,它只被创建一次,因此不应该引起泄漏。

getJSON匿名函数中的所有局部变量将在完成后被释放。getJSON调用中存活的唯一数据是你分配的:

olddata = json;

但是,每个后续的调用只是替换了前一个调用中的数据,因此以前的数据不再被引用和可回收,不能被垃圾回收器回收。
这里没有DOM操作,因此没有机会在DOM和JS之间产生交叉或循环引用。
我的结论是,我没有看到任何泄漏的迹象。我看到有很多使用临时内存的东西,所以我怀疑你在进程内存使用方面看到的是堆增长,但增长的方式是可以重复使用增长的内存。如果浏览器也缓存JSON结果,则可能会看到内存缓存增长。
不幸的是,在今天的浏览器中,很难判断它是否真的是内存泄漏,还是由缓存、一般堆等导致的浏览器内存的临时扩展。在极端情况下,您可以将所有缓存设置为非常小,并运行很长时间(数十万次迭代)。如果它不是泄漏,内存使用应该最终平稳。如果是泄漏,内存使用应该相对线性增长。
免责声明:这里唯一的免责声明是,我假设jQuery函数$.getJSON()本身不会泄漏,并且总是以清理它创建的闭包的方式完成,即使ajax调用不成功。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接