javascript垃圾回收由引擎自动管理,基于可达性判断对象是否可回收;从全局对象、调用栈变量等根出发,能通过引用链访问到的对象被保留,否则被标记清除。

JavaScript 的内存管理是自动的,开发者不直接控制分配和释放,但理解垃圾回收(GC)机制能帮你预判内存行为、避免泄漏。核心在于:引擎只在对象“不可达”时才回收,而不是“没用”时——这个判断逻辑决定了内存是否真正释放。
内存分配:栈与堆分工明确
基本类型(数字、字符串、布尔值)直接存在栈里,函数执行完就自动清掉;引用类型(对象、数组、函数)实际数据存在堆里,栈中只存一个地址指针。比如:
let user = { name: 'Alice' }; —— { name: 'Alice' } 在堆中,user 在栈中保存指向它的地址。
这意味着:栈内存释放快且确定;堆内存是否释放,完全取决于有没有变量或结构还能顺着引用链找到它。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
可达性是回收的唯一标准
GC 不靠“用了多久”或“是不是局部变量”来判断,而是从一组根对象(global、当前调用栈里的变量、DOM 节点等)出发,沿着所有引用关系往下找。能被找到的对象就是“可达的”,其余都是垃圾。
- 函数执行结束,其内部局部变量若没被外部闭包或全局变量引用,就立刻不可达
- obj1 = obj2; 后,原 obj1 指向的对象如果再无其他引用,就变成不可达
- DOM 元素被 removeChild 或 innerHTML = '' 移除,但如果 JS 还有变量引用它,它依然在内存中
主流回收策略:标记-清除为主
现代引擎(如 V8)主要用标记-清除(Mark-and-Sweep),步骤很清晰:
- 暂停 JS 执行(极短时间),从根开始遍历,给所有可达对象打上“活跃”标记
- 扫描整个堆,把没被打标记的对象内存直接清空并归还
- 不依赖引用计数(老式 IE 曾用),因此不会因循环引用漏回收
补充说明:V8 还结合分代回收——新创建的小对象放在“新生代”,回收频繁;长期存活的对象晋升到“老生代”,回收间隔更长、更省资源。
哪些操作容易让内存无法释放
不是 GC 失效,而是你无意中维持了可达性:
- 忘记清除定时器:setInterval 回调里引用了大对象,定时器没 clearInterval,对象一直可达
- 事件监听未解绑:给 DOM 绑了 addEventListener,组件卸载后没移除,DOM 和回调函数都卡在内存里
- 意外挂到全局:比如漏写 let/const,data = {...} 会变成 window.data,永不回收
- 闭包保留大对象:函数返回一个内部函数,而该函数又引用了函数内定义的大数组或缓存,外部调用后这个闭包一直活着,数组也跟着活
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










