Javascript具有周期性的自动垃圾收集机制,执行环境会负责管理代码运行过程中使用的内存。
常用的垃圾收集方式是 标记清除(mark-and-sweep)。当变量进入环境,就将这个变量标记为“进入环境”。离开环境就标记“离开环境”。
工作流程:
- 垃圾收集器在运行时给内存中的所有变量加上标记。
- 去掉环境中的变量和被环境中的变量引用的变量标记。
- 后来再加上的变量会被视为准备删除的变量。
- 销毁带标记的值并回收他们所占用的空间。
引用计数:
不太常用的垃圾收集策略(reference counting)。意为:跟踪记录每个值被引用的次数。
工作流程:
- 声明一个变量并将一个引用类型值赋给该变量,则这个值的引用次数为1。
- 同一个值若再次赋给另一个变量,则改值引用次数加1。
- 包含对这个值引用的变量又取得了另一个值,引用次数减1。
- 当引用次数变为0,则无法在访问这个值,就可以将其占用的内存回收回来。
- 垃圾回收器下次再运行时,释放引用次数为零的值被占用的内存。
对内存使用不当的话会造成内存泄露。以下这几种情况会造成内存的泄漏:
- 意外的全局变量引起的内存泄漏。
原因:全局变量,不会被回收。
解决:使用严格模式避免。
- 闭包引起的内存泄漏
原因:闭包可以维持函数内局部变量,使其得不到释放。
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。
- 没有清理的DOM元素引用
原因:虽然别的地方删除了,但是对象中还存在对dom的引用
解决:手动删除。
- 被遗忘的定时器或者回调
原因:定时器中有dom的引用,即使dom删除了,但是定时器还在,所以内存中还是有这个dom。
解决:手动删除定时器和dom。
- 子元素存在引用引起的内存泄漏
原因:div中的ul li 得到这个div,会间接引用某个得到的li,那么此时因为div间接引用li,即使li被清空,也还是在内存中,并且只要li不被删除,他的父元素都不会被删除。
解决:手动删除清空。