js 内存泄露与垃圾回收
2023-03-11 本文已影响0人
欢西西西
不再使用的对象无法被垃圾回收机制回收,就是内存泄露(因为指针没有被置为null,就会导致无法释放掉它指向的内存)
一、常见内存泄露的情况
- 函数内部意外的全局变量
function add() {
num = 10;
}
- 闭包(利用闭包特性去实现保存变量的情况并不算是内存泄露)
- 未被清空的定时器
- 未被解绑的事件监听
在Vue中,我们可以使用一个全局vue对象作为eventBus,组件中通过$on监听了某个事件,那么事件处理函数会保存在这个全局vue对象里;如果组件被销毁时未解绑事件,那么第二次创建该组件时,会出现重复绑定的情况,因为之前存的事件处理函数并未被销毁
- 对不再使用的DOM的引用
如果dom已经从文档中被删除,但js中依然存在对这个dom的引用,那么它也不会被垃圾回收,同时这个dom上注册的事件监听也不会被回收。如果这个节点不再需要,则引用应置为null


- 打开控制台的console.log()语句
Vue项目中最容易出现内存泄漏的情况如下:
- 监听在window/document的事件未解绑,而组件已销毁
- EventBus的事件没有解绑,而组件已销毁
- Vuex的$store watch了之后没有unwatch
- 模块形成的闭包,使用完之后没有置为null
- 组件中创建的某对象引用了dom,但dom被清除时(例如使用v-if)没有销毁对象
二、定义内存不再使用的标准
1. 引用计数
跟踪记录每个值被引用的次数(多1次引用加1,少1次引用减1),如果这个次数是0了,就可以清除;
但有一个致命问题:循环引用。如果2个对象互相引用,但又无法再访问到这2个对象的时候,就无法清除了,导致内存泄露(访问不到,也不会被清除)

2. 标记清除法 mark and sweep
遍历所有可访问的对象、回收已不可访问的对象。
将不再使用的对象定义为无法到达的对象,从根部对象开始检测,能到达的对象都是要使用的对象,不能到达的,标记为可以清除的
