堆heap
是动态分配的内存, 大小不定也不会自动释放, 栈stack
为自动分配的内存空间, 在代码执行过程中自动释放
栈区
在栈内存中提供一个供JavaScript代码执行的环境, 关于作用域以及函数的调用都是栈内存中执行的
JavaScript中基本数据类型String
, Number
, Boolean
, Null
, Underfined
, Symbol
, 占用空间小且大小固定, 值直接保存在栈内存中, 是按值访问, 对于Object
引用类型, 其指针放置于栈内存中, 指向堆内存的实际地址, 是通过引用访问
关于调用栈, 每调用一个函数, 解释器就会把该函数添加进调用栈并开始执行; 正在调用栈中执行的函数还调用了其他函数, 那么新函数也将会被添加进调用栈, 一旦这个函数被调用, 便会立即执行; 当前函数执行完毕后, 解释器将其清出调用栈, 继续执行当前环境下的剩余代码; 当分配的调用栈空间被占满时, 会引发堆栈溢出错误
let a = 1;
function s() {
let b = 11;
debugger; // 断点
}
function ss() {
s();
}
ss();
/*
...
Call Stack
> s (VM383:4)
ss (VM383:7)
(anoymous)(VM383:9)
Scope
Local
b: 11
this: Window
Global Window
...
...
*/
堆区
引用类型Object
堆变量占据空间大且大小不固定, 堆内存中存储实际对象, 在栈内存中存储对象的指针, 对于对象的访问是按引用访问的, 在堆区的内存不会随着程序的运行而自动释放, 这就需要实现垃圾回收机制的GC
, 需要注意点是在JavaScript中没有类似于C中的free()
函数去手动释放内存, 对于堆区内存回收全部需要通过JavaScript的垃圾回收机制去实现
在栈区中执行的变量等是通过值访问, 当其作用域销毁后变量也就随之销毁, 而使用引用访问的堆区变量, 在一个作用域消失后还可能在外层作用域或者其他作用域仍然存在引用, 不能直接销毁, 此时就需要通过算法计算该堆区变量是否属于不再需要的变量, 从而决定是否需要进行内存回收, 在JavaScript中主要有引用计数与标记清除两种垃圾回收算法