js中的垃圾都是自动的,我们不需要手动回收垃圾;通常认为对象不再被引用时是垃圾,对象从根上(全局对象)向下一级一级查找,不能被访问到的是垃圾
一、常见的垃圾回收算法(GC算法)
引用计数
标记清除
标记整理
分带回收
1、引用计数
核心思想:判断一个对象当前引用数是否为0
维护一个引用计数器,当引用关系变化时,修改引用数字,为0时,回收该对象所占的内存空间
优点:
发现垃圾时立即回收
最大限度减少程序暂停,因为在进行垃圾会收时,js程序暂停执行,引用计数时实时回收垃圾
缺点:
无法回收循环引用的对象,如果两个对象互相引用,引用计数不为0,也就不会被回收
由于需要维护一个引用计数器,消耗资源较大
2、标记清除
核心思想:分为标记和清除两个阶段,第一个阶段遍历所有对象,对能访问到的活动对象做一个标记,第二个阶段再遍历一次对象,对没有被标记的对象做清除,回收相应内存空间
优点:可以回收引用对象的内存空间
缺点:由于回收的内存都不是连续的,容易产生碎片化内存空间,浪费空间;两次遍历之间有一个时间间隔,不会立即回收垃圾对象
3、标记整理
核心思想:是对标记清除的增强,在清除阶段,先对内存空间做一个整理(移动对象位置),将不连续的内存变为连续的内存空间
优点:减少碎片化内存空间
缺点:不会立即回收垃圾对象;增加了移动对象环节,回收效率慢
二、V8垃圾回收策略
V8是一款主流的javaScript引擎,内存上线是1.5g(64位系统)
垃圾回收的策略采用分带回收的思想,将内存分为新生代和老生代,新、老生代使用不同的垃圾回收算法
新生代所占内存为32M(64位系统)或者16M(32位系统);新生代通常指的是存活时间较短的对象那个,例如函数的局部对象,当函数执行完成后,该对象就会被释放
1、新生代对象回收实现
采用复制算法+标记整理算法
新生代分为两个等大空间:from空间和to空间
活动对象都存储在from空间,to空间为空闲状态
使用标记整理算法后,将from空间的活动对象复制到to空间
from与to交换空间后,将from空间的内存释放掉,现在原来的to变为了from空间,from变为了to
在将from复制到to空间时,会有将新生代对象移动到老年代的情况,满足以下两点即可
一轮GC后还存活的新生代对象
to空间的使用率超过25%
2、老年代回收实现
采用标记清除、标记整理、标记增量算法
使用标记清除完成垃圾空间的回收
使用标记整理优化碎片空间
使用增量标记算法优化效率
增量标记算法:由于在进行垃圾回收时,js程序处于暂停执行的状态,如果垃圾回收的时间过长,程序会出现卡顿状态,所以将标记、清除的时间切割成适量的几段,可以降低程序卡顿的情况
三、js代码优化几点注意事项
1、慎用全局变量
2、通过原型新增方法
3、闭包容易出现内存泄漏
4、避免属性访问方法使用
5、for循环的优化,将数组长度缓存起来
6、forEach循环效率>for>for in
7、dom节点添加时要减少重绘和重拍
9、添加dom节点时先clone后添加
10、对象直接赋值替换new Object操作