在这种情况下,大多数垃圾收集不会做出任何的收集工作。换句话说,即使有不可用的引用需要收集,但是收集器不会进行收集。虽然这并不是严格的泄漏,但仍会导致内存使用率高于平时。
什么是内存泄漏?
内存泄漏是应用程序使用过的内存片段,在不再需要时,不能返回到操作系统或可用内存池中的情况。
编程语言有各自不同的内存管理方式。但是是否使用某一段内存,实际上是一个不可判定的问题。换句话说,只有开发人员明确的知道是否需要将一块内存返回给操作系统。
四种常见的JavaScript内存泄漏
1:全局变量
JavaScript以一种有趣的方式来处理未声明的变量:当引用未声明的变量时,会在全局对象中创建一个新变量。在浏览器中,全局对象将是window,这意味着
function foo(arg) { bar = "some text"; }
相当于:
function foo(arg) { window.bar = "some text"; }
bar只是foo函数中引用一个变量。如果你不使用var声明,将会创建一个多余的全局变量。在上述情况下,不会造成很大的问题。但是,如若是下面的这种情况。
你也可能不小心创建一个全局变量this:
function foo() { this.var1 = "potential accidental global"; } // Foo called on its own, this points to the global object (window) // rather than being undefined. foo( );
你可以通过在JavaScript文件的开始处添加‘use strict';来避免这中错误,这种方式将开启严格的解析JavaScript模式,从而防止意外创建全局变量。
意外的全局变量当然是一个问题。更多的时候,你的代码会受到显式的全局变量的影响,而这些全局变量在垃圾收集器中是无法收集的。需要特别注意用于临时存储和处理大量信息的全局变量。如果必须使用全局变量来存储数据,那么确保将其分配为空值,或者在完成后重新分配。
2:被遗忘的定时器或回调
下面列举setInterval的例子,这也是经常在JavaScript中使用。
对于提供监视的库和其它接受回调的工具,通常在确保所有回调的引用在其实例无法访问时,会变成无法访问的状态。但是下面的代码却是一个例外:
var serverData = loadData(); setInterval(function() { var renderer = document.getElementById('renderer'); if(renderer) { renderer.innerHTML = JSON.stringify(serverData); } }, 5000); //This will be executed every ~5 seconds.
上面的代码片段显示了使用引用节点或不再需要的数据的定时器的结果。
该renderer对象可能会在某些时候被替换或删除,这会使interval处理程序封装的块变得冗余。如果发生这种情况,那么处理程序及其依赖项都不会被收集,因为interval需要先停止。这一切都归结为存储和处理负载数据的serverData不会被收集的原因。