JS引擎通过可达性判断内存是否需要保留:
从根对象(Roots)出发,能访问到的对象标记为"存活",无法访问的即为"可回收"
这里的“根”可以理解为浏览器或 Node.js 中的全局对象,比如 window、globalThis,或者正在执行的函数上下文
原理:
优点:完美解决循环引用(互相引用但都不可达时,都不会被标记)
V8将内存堆分为两个区域,针对性优化:
存放的是:临时变量、局部变量、短时间内用完就丢弃的对象
存放的是:全局变量、闭包变量、长期存活的对象
V8 为老生代设置了内存阈值,当老生代中的对象数量超过这个阈值,就会触发一次 Major GC(全量垃圾回收)。
当新生代的对象要晋升到老生代,但老生代空间不足时,也会强制触发老生代 GC。
浏览器会监听系统内存状态:
内存泄漏:不再需要的内存,由于某种原因未被GC回收,导致内存占用持续增长
function leak() {
// 没有 var/let/const,挂载到 window
accidentalGlobal = new Array(1000000);
// 函数结束,数组仍被全局引用 → 泄漏
}
// 修复:使用严格模式 'use strict' 禁止隐式全局变量let cache = {};
function addElement() {
const div = document.getElementById('container');
cache.div = div; // JS 持有 DOM 引用
div.remove(); // 从 DOM 树移除
// 但 cache.div 还在引用,DOM 节点无法回收 ❌
}
// 修复:移除时同步清除引用
function fixedAddElement() {
const div = document.getElementById('container');
cache.div = div;
div.remove();
delete cache.div; // 或 cache.div = null
}let userCache = new Map();
function cacheUser(id, data) {
userCache.set(id, data); // 只增不减
}
// 使用 WeakMap 自动回收
let userWeakCache = new WeakMap(); // 键为对象,弱引用