S01E01-从堆、栈、内存机制开始
JavaScript 中有三种数据结构: 栈(stack) 、堆(heap)、 队列(queue)。它们是我们理解 JavaScript 核心的基础。
本篇将围绕栈(stack) 、堆(heap),以及 JavaScript 的内存机制来展开。队列(queue)将会放在本系列的第四部分-异步和性能来讲解。
栈(stack)
栈(stack)有三层含义:
含义一:数据结构
栈的第一种含义是表示的是数据的存放方式。
栈存储数据的特点:LIFO规则,即后进先出(Last In, First Out)。数据存储时只能从顶部逐个存入,取出时也只能从顶部逐个取出。顶部是唯一的出口。
借助前端大神的乒乓球盒子的栗子:

如图所示,我们只能从栈顶取出或放入乒乓球,最先放进盒子的总是最后才能取出。
乒乓球的放入/取出,在栈中可称为入栈/出栈。
含义二:函数调用栈(call stack)
stack 的第二层含义是代码的一种运行方式。
通过栈的方式来管理代码的执行顺序,是栈数据结构的一种实践,遵循LIFO规则。
含义三:内存空间
stack 的第三种含义是存放数据的一种内存区域。
在 JS 运行时,需要内存空间存放数据。一般来说,内存空间又被分为两种:栈内存(stack)、堆内存(heap)。
栈内存的特点:
- 一般存放基本类型的值和引用类型的引用地址(指针)。
- 是有序的
- 在内存中占据空间小,大小固定
例如,最简单的,声明一个变量a:
1 | var a = 12 |
如图所示,会在栈内存中开辟一块空间存储 12,把存储的 12 赋值给 a。
我们需要注意的是:
JS 允许直接操作保存在栈内存中的值。因此,基本类型是按值访问的。
堆(heap)
堆只有一层含义:内存空间。堆内存的特点:
- 一般存放引用类型的值
- 是无序的
- 引用类型的值没有固定大小,可扩展(一个对象我们可以添加多个属性),占据空间大
为了更好的理解堆内存空间,我们看一个最简单的:
1 | var obj = { m : 20 } |
声明一个变量 obj,会在堆内存中开辟一块新的空间,把对象中的键值对依次存储进来(同时,为这个空间加了一个16 进制的地址的标记),这个地址和这块空间是关联在一起的,如图所示。
注意:这个空间地址是被保存在栈内存中的。
我们需要注意的是:
JS 不允许直接访问堆内存中的位置。在操作对象时,实际上是操作的是对象的引用。因此,引用类型是按引用访问的。
内存空间管理
不管是栈内存,还是堆内存,都是由系统自动分配和自动释放的。了解内存的管理机制,对于提高我们的页面性能尤其重要。
内存的生命周期一般有三步:
- 分配:当我们声明变量、函数、对象时,系统会自动为它们分配内存
- 使用:即读/写内存,也就是使用变量、函数等
- 回收:使用完毕,由垃圾回收机制自动回收不再使用的内存
分配和使用都很好理解。对于内存的释放回收,我们接下来重点看一下。
垃圾回收机制
垃圾回收机制:
浏览器会在空闲时,遍历所有的内存空间,发现谁不被占用,就会自主的进行内存回收。
该机制的核心思想就是找到谁不被使用,因此我们可以通过标记清除的算法来标记哪些内存不再被占用。
- 对于堆内存,我们可以将占用它的变量手动赋值为 null 来标记清除。
- 对于栈内存,局部环境中,只有当函数执行完成后,函数局部环境声明的变量不再需要时,才会被释放(特殊不销毁的情况:闭包)。全局环境只有当页面关闭时才会解除变量引用。因此,开发者应尽量避免创建全局变量。
垃圾回收算法除了”标记清除”,还有一种”引用计数”,不常用,仅作了解。
内存泄漏
由于疏忽或错误造成程序未能释放那些已经不再使用的内存,造成内存的浪费。
引起内存泄漏的情况:
- 在函数内部,不带var声明变量,给 window 添加了属性
1
2
3
4
5function foo() {
this.a = 'window.a';
b = '全局变量';
}
foo(); - 当不需要 setInterval 或者 setTimeout 时,定时器没有被 clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。
- 闭包可以保存内部状态,使其得不到释放,造成内存泄漏。
- 没有清理 DOM 元素引用,手动清除为 null 即可
结束
重学 JS 系列 预计 25 篇左右,这是一个旨在帮助大家,其实也是帮助我自己捋顺 JavaScript 底层知识的系列。主要包括变量和类型、执行上下文、作用域及闭包、原型和继承、单线程和异步、JS Web API、渲染和优化几个部分,将重点讲解如执行上下文、作用域、闭包、this、call、apply、bind、原型、继承、Event-loop、宏任务和微任务等比较难懂的部分。让我们一起拥抱整个 JavaScript 吧。
大家或有疑问、或指正、或鼓励、或感谢,尽管留言回复哈!非常欢迎 star 哦!

