JavaScript变量生命周期本质是引擎自动管理内存的全过程:声明时按类型在栈或堆分配内存;运行时依可达性判断存活性;退场时通过标记-清除算法回收不可达对象,非实时但可靠。

变量生命周期和垃圾回收机制,本质上是 JavaScript 引擎自动管理内存的一整套逻辑:变量从诞生、存活到退场,全由引擎按规则决定,开发者不手动分配或释放,但得知道“它为什么还在”“它为什么没被收走”。
变量怎么诞生:声明那一刻就分内存
你写 let x = 5 或 const obj = {a: 1} 的瞬间,引擎已做完内存分配:
- 基本类型(number、string、boolean 等)直接存进栈内存,值本身就在那儿;
- 引用类型(对象、数组、函数等)实际数据存在堆内存,栈里只存一个指向它的地址;
- 这个过程全自动,不需要 new 或 malloc,但类型不同,存放位置和后续回收方式就不同。
变量怎么存活:只看“能不能被找到”
引擎不关心变量有没有 let 声明,只认一个标准:可达性(Reachability)。只要能从根对象出发顺藤摸瓜访问到,就算“在职”:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 根对象包括:全局对象(如 window)、当前执行函数的局部变量、调用栈里的活跃函数、DOM 树的根节点;
- 一旦所有引用链断开——比如
obj = null、函数执行完且没闭包捕获、DOM 元素被移除但监听器没解绑——对象就变成“找不到的人”,进入待回收队列; - 闭包是例外:内部函数持续引用外部变量,会让那些本该随函数结束而消失的局部变量继续留在堆中。
变量怎么退场:标记-清除不是实时,但很靠谱
现代引擎(如 V8)主要用标记-清除(Mark-and-Sweep)算法,分两步:
立即学习“Java免费学习笔记(深入)”;
- 标记阶段:从根出发遍历,把所有能到达的对象打上“活跃”标签;
- 清除阶段:扫一遍堆,把没被打标的对象内存清掉,空出来复用;
- 它天然处理循环引用(
a.ref = b; b.ref = a),只要两者都脱离根链,哪怕彼此引用,也会一并回收; - 回收不每行代码后都发生,而是在内存压力上升或空闲时触发,有延迟但稳定可靠。
哪些操作容易让变量“赖着不走”
有些写法看似正常,实则悄悄延长了对象寿命,埋下内存泄漏隐患:
- 把大对象挂到全局或
window上(如window.cache = hugeData); - 用
setInterval但忘了清理,回调函数一直持有外部引用; - DOM 元素被移除后,事件监听器没用
removeEventListener解绑; - 控制台里无意保留了对大对象的引用(比如在调试时点了展开),也可能暂时阻止回收。

















