因为字符串、对象和数组没有固定大小,因此当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次建立字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们可以被再用,不然,JavaScript的解释器将会消耗完系统中全部可用的内存,形成系统崩溃。 ---《JavaScript权威指南(第四版)》javascript
JavaScript的解释器能够检测到什么时候程序再也不使用一个对象了,当他肯定了一个对象是无用的时候,他就知道再也不须要这个对象,能够把它所占用的内存释放掉了。例如:java
var a = "before"; var b = "override a"; var a = b; //重写a
这段代码运行以后,“before”这个字符串失去了引用(以前是被a引用),系统检测到这个事实以后,就会释放该字符串的存储空间以便这些空间能够被再利用。node
最常采用的垃圾回收有两种方法:标记清除、引用计数git
当执行流入到一个函数中时,会建立该函数的执行环境,执行环境中的变量都会被标记为“进入环境”,从逻辑上讲,永远不能释放“进入执行环境”变量所占用的内存。由于只要执行流入相应的执行环境,就可能会用到这些变量。
垃圾收集器在运行的时候会给存储在内存的中的变量都加上标记。而后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此以后再被加上标记的变量将被视为准备删除的变量。最后,垃圾收集器完成内存清除工做,销毁那些带标记的值并回收它们所占用的内存空间。github
另外一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每一个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,若是包含对这个值引用的变量又取得了另一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,于是就能够将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。chrome
可是用这种方法存在问题:数组
function problem(){ var objA = new Object() var objB = new Object() objA.someOtherObject = objB objB.someOtherObject = objA }
在这个例子中,objA和objB经过各自的属性相互引用;也就是说这两个对象的引用次数都是2。在采用引用计数的策略中,因为函数执行以后,这两个对象都离开了做用域,函数执行完成以后,objA和objB还将会继续存在,由于他们的引用次数永远不会是0。这样的相互引用若是说很大量的存在就会致使大量的内存泄露。缓存
将全局变量做为缓存数据的一种方式,将以后要用到的数据都挂载到全局变量上,用完以后也不手动释放内存(由于全局变量引用的对象,垃圾回收机制不会自动回收),全局变量逐渐就积累了一些不用的对象,致使内存泄漏闭包
var x = []; function grow() { x.push(new Array(1000000).join('x')); /* 使用x数组进行某些操做 */ setTimeout(grow, 1000); } grow()
(function () { var nodes = ''; var item = { // 为了凸显 name: new Array(1000000).join('x') } nodes = document.getElementById("nodes") nodes.item = item nodes.parentElement.removeChild(nodes) })()
notes变量指向的是页面中的一个元素(也是内存中的一块空间),当将 notes 对应的元素从页面中移除后,其在内存中对应的空间因为仍然由notes变量指向(引用),所以垃圾回收机制不会将这块内存空间回收,从而致使内存泄漏ide
var someResource = getData(); setInterval(function() { var node = document.getElementById('Node'); if(node) { node.innerHTML = JSON.stringify(someResource)); } }, 1000);
这样的代码很常见, 若是id为Node的元素从DOM中移除, 该定时器仍会存在, 同时, 由于回调函数中包含对someResource的引用, 定时器外面的someResource也不会被释放.
var theThing = null var replaceThing = function () { var originalThing = theThing var unused = function () { if (originalThing) console.log("hi") } theThing = { longStr: new Array(1000000).join('*'), someMethod: function () { console.log(someMessage) } }; }; setInterval(replaceThing, 1000)
这种内存泄漏的分析请参考here
《JavaScript权威指南》
javascript典型内存泄漏及chrome的排查方法