参考:极客时间-浏览器工作原理及实践
内存泄漏
内存泄漏:指代码使用完毕后没有被回收释放(指任何对象在您不再拥有或需要它之后仍然存在。)
哪些操作会造成内存泄漏?
-
setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
-
没用的闭包存在全局变量中
-
控制台日志
-
循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
避免内存泄漏:
- 将不再使用的变量赋值为null
观察数据判断内存泄漏工具:
- DynaTrce(IE)profiles
- Chrome 的 Performance
垃圾回收
垃圾回收,释放内存空间
垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为0(没有其他对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存即可回收。
垃圾回收分类:
手动垃圾回收:c/ c#
自动垃圾回收:js、Java、python (垃圾数据由垃圾回收器来释放)
栈回收
JS 引擎 会自动对栈的进行垃圾回收
堆回收:垃圾回收器
堆分为老生代和新生代区域
标记清除(mark and sweep):
-
这是 JavaScript 最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。
-
垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了
引用计数(reference counting):
- 在低版本 IE 中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。
- 在IE中虽然JavaScript对象通过标记清除的方式进行垃圾回收,但BOM与DOM对象却是通过引用计数回收垃圾的,也就是说只要涉及BOM及DOM就会出现循环引用问题。
老生代:主垃圾回收器
老生代数据:1. 大的对象会直接放在老生代区域中 2. 新生代中晋升的对象
老生代处理流程:(标记-清除、标记-整理 算法)
1、标记活动对象和非活动对象
2、清理非活动对象
3、处理内存碎片,将对象串起来
新生代:副垃圾回收器
新生代处理流程:(scavenge算法 操作频繁)
1、新生代分为对象区域和空闲区域;当对象区域数据满了才会进行垃圾回收
2、标记活动对象和非活动对象
3、将活动对象复制到空闲区域,复制过程中清理非活动对象,这样活动对象在空闲区域也是连成串的,就不存在内存碎片
4、将对象区域与空闲区域进行调换,空闲区域变对象区域,对象区域变空闲区域;这样角色翻转可以让两个区域无限重复使用
缺点:复制活动对象需要时间成本,为了提高效率,对象区域一般会设置的比较小
优化:对象晋升策略:经过两轮垃圾回收依然存在的活动对象会被移动到老生代
全停顿:
v8进行垃圾回收算法执行时会将正在执行的js脚本都暂停下来,等垃圾回收完毕后再恢复脚本执行;新生代区域小这样操作影响不大,老生代会导致页面卡顿现象
优化:增量标记算法:垃圾回收标记分为一个个小的,与js脚本交替执行,直到标记阶段完毕。