JS 垃圾回收算法有哪些
function fn() {
const a = 'aa'
console.log(a)
const obj = { x: 100 }
console.log(obj)
}
fn1()
function fn2() {
const obj = { x: 100 }
window.obj = obj // 符合用户预期
}
fn2()
function getDataFns() {
const data = {}
return {
get(key) {
return data[key]
}
set(key, value) {
data[key] = value
}
}
}
const { get, set } = getDataFns()
set('x', 100)
get('x')
- 引用计数(之前) 每个对象都有一个引用计数器,记录有多少个变量或对象引用了它。当变量赋值为对象时,引用计数 +1。当变量被赋值为其他值(或离开作用域、被设为 null)时,原引用的对象引用计数 -1。当引用计数为 0 时,对象被判定为“可回收”,其内存会被垃圾回收器释放。
let a = { x: 100 } // 计数: 1
let a1 = a // 计数: 2
a = 10 // 计数: 1
a1 = null // 计数: 0
无法解决循环引用问题
function fn3() {
const obj1 = {}
const obj2 = {}
obj1.a = obj2
obj2.a = obj1
}
fn3()
- 标记清除(现代)
- 标记阶段
垃圾回收器从根对象(如全局对象window)开始,递归地标记所有从根对象可达的对象,这些对象是活动对象,即仍在使用中的对象。
那些没有被标记的对象就是不可达的,被认为是垃圾对象,即不再被程序使用的对象。 - 清除阶段
垃圾回收器会遍历整个堆内存,将所有未被标记的垃圾对象所占用的内存空间释放掉,回收这些内存以便后续重新分配使用。
- 标记阶段
JS 闭包是内存泄露么?
在 JavaScript 中,闭包本身不是内存泄漏,但不当使用闭包可能导致内存泄漏。
如何检测 JS 内存泄露
打开浏览器开发者工具(通常是按 F12 或 Ctrl + Shift + I)。 切换到 Memory 面板。 进行一次初始的内存快照(点击 Take snapshot)。 执行你怀疑可能导致内存泄露的操作。 再进行一次内存快照。 对比两次快照,查看哪些对象在操作后没有被回收,并且数量持续增加。
内存泄露的场景
- 被全局变量、函数引用,组件销毁时未清除
- 被全局事件、定时器引用,组件销毁时未清除
- 被自定义事件引用,组件销毁时未清除