Javascript的世界中,隐藏了不少内存陷阱,不能获得合理释放的内存会埋下各类隐患,本文旨在以实用角度去解读Js涉及到的内存,且看勇士如何斗恶龙~javascript
本文能够看作是以前那篇勇士斗恶龙之没那么复杂的Js闭包的后续篇,在思考闭包中内存的问题时,有了写此文的冲动. 前端
学以至用,从实用的角度出发咱们最须要关注的就是内存回收用什么用处?咱们平常工做中好像不须要咱们本身去处理Javascript中的内存,它会自动回 收的.若是你问Javascript内存回收,必定会有TX鄙视的告诉你,这个会自动回收,不须要咱们本身处理. java
Javascript中的内存,真的不须要咱们关注吗??? 程序员
一般这种自问自答的结果,就是会给出一个与问题相反的答案,也就是固然须要!Javascript虽然会自动处理内存,但不是完美的,它存在必定的缺陷.另外一方面,咱们不能由于无知而无畏,由于可能不少莫名其妙的问题就是这样出现的. 算法
内存-那些咱们忽略的就是咱们要拯救的 编程
在平时的编码中咱们无时无刻不在执行这样的一个过程,分配内存 -> 使用内存 -> 回收内存.如此反复的过程在不断持续着,每个数字,字符串,对象,数组,方法都占用着计算机的内存.前端编程由于你的Js代码大部分运行在客户端浏览 器,因此虽然你没有占用服务器的内存,但是你占用了使用者的内存.即便在硬件配置愈来愈高的今天,也不能彻底保证咱们产品的使用者不是古老的机器,何况你 也应该考虑到移动手机的性能.也不是说每一台机器都配有4G以上的内存供你挥霍,我一直认为好的程序员对待内存要保持一个吝啬的心态. 数组
Javascript在分配内存这一过程当中,会根据不一样的数据类型进行分配.像基本数据类型会分配在栈内存,引用数据类型分配在堆内存中.引用对于理解内存是一个很重要的概念,我最先对引用的理解来自于C里面的指针,最好找资料仔细了解一下. 浏览器
1
2
3
4
|
var
obj = {name:
"benze"
};
var
car = obj;
//这里car就是指向了obj所建立的那个对象所在的内存空间,也就是说此时obj和car都指向了同一块内存.
//在内存管理的环境中,若是一个对象有权限去访问另外一个对象,就叫作一个对象引用另外一个对象
|
咱们平时在使用定义变量,函数或者对象的时候,都在进行各类的内存分配,可是一般不须要写代码去回收,由于咱们知道它是自动回收的.这里我得强调,自动不表明咱们就不要考虑内存回收了. 服务器
使用内存-也就是那些读读写写
闭包
关于内存的使用,个人理解就是对于已经开辟好内存空间的那些值,进行一些读写操做.这一过程当中可能还有对象引用的改变等等,由于这个不是本文重点,不加以赘述.
内存回收 === 屠龙之术?
话说古时候有人散尽家财学的屠龙之术,技成以后却发现无龙可屠.那Javascript既然有着自动回收的内存管理,咱们学习内存回收岂不也是同样,反正 它能正常回收就行呗,咱们管它是怎么回收的呢.可是问题是我以前提到过,Javascript的垃圾回收机制有必定的局限性和缺陷,有一些状况会使得内存 得不到释放而持续增长,这时候咱们就须要人为的处理它.
引用计数的回收机制
上文提到过引用的概念,Javascript的内存回收的算法主要就依赖于引用,当代码生成一个新的内存驻留项时(如一个对象),系统就会为它开辟一块内 存空间.由于这个对象可能会被传递给其余函数,或者对象.因此可能不少代码都会指向这个对象的内存空间.javascript的垃圾回收器跟踪这些指向, 当最后一个指向都被断开废弃的时候,这个对象所占用的空间就会被释放.
这是一种比较简单而且清晰的算法,看上去感受没什么问题,可是若是出现这种状况呢?
1
2
3
4
|
var
a = {name:
'a'
};
var
b = {name:
'b'
};
a.bname = b
b.aname = a;
|
代码看着很别扭是吧,可是若是真有这种状况呢,彼此引用.这样的状况,javascript的的回收就对a和b没有办法了.对于这种循环引用,实在是各种垃圾自动回收的缺陷.
真实状况的内存没法回收
也许上面说的那种状况对于你来讲永远不可能发生,平时注意点也许就避开了,可是总有些状况,也许你写了好久本身都没发现.在稍微旧一点版本的IE下,Javascript的对象是经过标记清除的,BOM和DOM对象倒是经过引用计数,涉及到DOM或者BOM的时候就容易出现循环引用.上代码瞅瞅:
1
2
3
4
5
6
|
<span></span>$(document).ready(
function
(){
var
div = document.getElementById(
"mydiv"
);
div.onclick =
function
(){
console.log(
"div"
);
}
});<span></span>
|
当指定的单击事件处理程序时,建立了一个在其封闭的环境中包含div变量的闭包环境.而div也包含一个指向闭包的引用(onclick属性自身),这就致使了内存都不能获得释放.固然解决方法很简单:
1
2
3
4
5
6
7
|
$(document).ready(
function
(){
var
div = document.getElementById(
"mydiv"
);
div.onclick = saydiv;
});
function
saydiv(){
console.log(
"div"
);
}
|
此时由于saydiv函数不在包含div的引用,因此没有造成循环,内存能够获得释放.
可能不少人都知道将一个对象置为null,那么它的内存就会回收.这是由于变量的指向了一个null,那么它原来指向的那块内存空间就会由于没有被指向,或者说没有被引用,而被垃圾回收掉.
标记清除-手动内存回收居然仍是屠龙之术?
从2012年起现代浏览器中,对于Javascript垃圾回收的机制进行了更新.再也不使用引用计数的算法,而是改成使用标记清除的方式.好比定义一个变 量,那么当它进入执行环境时,会被垃圾回收器标记为"进入环境",当其离开环境好比函数执行完毕的时候,标记为"离开环境".垃圾回收机器就会在这些"离 开环境"的变量中挑选出来须要回收掉的变量用于释放内存.
这存在一个挑选标准,它不会再去计 算引用的数量.而是从全局对象(根节点)开始寻找,找到全部可得到的对象和全部不可得到的对象.也就是它从以前判断"对象是否被须要"变成"对象是否能够 得到".这么理解,零引用的对象老是不可得到的,可是不可能得到的对象不必定零引用.
如此除了在比较低版本的IE的状况下,Javascript的自动回收机制就足以应付大多数状况了.在高级一点的IE中对于内存回收也有很大的进步,因此仍是推荐大多数状况下不要手工的回收垃圾.
尾笔
原本不打算写这段尾笔,不过为了不本文有有始无终的嫌疑,仍是要补充说明一下.首先是大部分现代浏览器都已经对内存作了很好的处理,因此大多数状况下不 须要咱们手工执行.其次本文的目的在于概括总结,而不是非要写出什么特殊东东.最后写此文也是为了给我本身和看过的人提个醒: