内存数据结构
- 栈:由操作系统自动分配释放 ,存放函数的参数值,局部变量等。
js中用来存储基本数据类型,它们占据空间小、大小固定,被频繁使用。number
、string
、boolean
、undefined
、null
、symbol
- 堆:一般由程序员分配释放,生命周期由垃圾回收算法决定。
js中用来存储引用数据类型,它们占据空间大、大小不固定。object
、array
、function
内存溢出/泄露
内存溢出:已有的数据超过了其获得到的内存所能存储的范围
内存泄露:不再用到的内存没有及时释放,导致占用的内存不能使用或回收。
如下原因会导致内存泄露:
- 全局变量不会被回收
- 闭包可以维持函数内局部变量,使其得不到释放
- 未清理的DOM元素的引用
比如删除DOM时,事件未清除 - 被遗忘的计时器
- 控制台日志
- 循环引用(两个对象相互引用)
引用计数机制时会产生此问题,但在标记清除机制中已被解决
垃圾回收机制 GC (Garbage Collection)
js创建一个对象时,会自动为其分配适当的内存,垃圾回收器定期扫描对象,判断对象是否可以回收,释放他们所指向的内存,防止内存泄漏。有以下两种方式:
1. 引用计数 Reference Counting (低版本IE)
跟踪一个变量的引用次数,当引用次数为0时就将其回收。
这种方式不能解决循环引用的问题,容易引起内存泄漏。
1 | // 每次调用f(), a b都互相引用,这部分内存永远不会被释放 |
2. 标记清除 Mark and Sweep (主流方式)
从全局作用域开始一层层往下标记能引用到的对象,未被标记的对象为不可访问的,被删除。解决了循环引用导致内存泄露的问题。

V8 引擎
chrome的js解释器,虽然十分强大,但存在内存溢出的隐患,64位机器只被分配1.4G的内存,在客户端浏览器绰绰有余,但在后端NodeJs上就不够了。
V8内存空间分为新生代和老生代:
1. 新生代内存空间:存放存活时间较短的对象
Scavenge 算法: from相当于清空区,to相当于安全区

2. 老生代内存空间:存放存活时间较长的对象
标记清除GC
标记存活对象,未标记的被清除。垃圾回收后内存会出现不连续的情况标记合并GC
将清除后保留下来的对象往堆的另一端移动,解决内存碎片化问题
3. 新生代晋升到老生代
- 新生代垃圾回收中,若对象之前被清理过,那么将其晋升到老生代内存中
- from和to反转过程中,若to使用量超过25%,就将from中对象晋升到老生代