持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
大家好,我是晚天。
堆和栈是两个令人迷惑的概念,堆和栈都是用于动态分配和释放数据的专用内存区域。到底 JavaScript 中的堆和栈有何作用?又有哪些区别呢?
接下来,我们将进行探讨。
内存生命周期
了解堆栈之前,我们要先了解堆栈遵循的内存声明周期。
在 JavaScript 中,当我们创建变量、函数等时,JavaScript 引擎会为其分配内存,当不再需要时会释放内存。
分配内存是在内存中预留空间的过程,释放内存则是释放内存空间。
内存声明周期为:
- 分配内存。为我们创建的变量、函数等分配内存空间;
- 使用内存。读取或赋值均会使用内存;
- 释放内存。内存空间使用结束,会被释放,以备后续使用。
JavaScript 有两个地方可用于存储数据:堆内存和栈内存。
栈:静态内存分配
栈是一个 LIFO(Last in,First out,后进先出)的数据结构,用于存储静态数据。静态数据是在编译时就可以确定大小的数据。在 JavaScript 中,包含基础数据类型(string、number、boolean、undefined、null)以及指向对象和函数的引用。
基础数据类型遵循按值传递的规则,每次赋值都会在栈中创建新的存储空间。
静态数据的大小不会变化,因此可以分配固定大小的内存空间。在执行前分配内存的过程被称为静态内存分配。
堆:动态内存分配
堆是一种无顺序的存储结构。堆用于存储对象和函数,堆所分配的内存是不固定大小的,而是按需分配。这种内存分配方式被称为动态内存分配。
堆栈对比
堆 | 栈 | |
---|---|---|
存储对象 | 对象和函数 | 基础类型和指向对象或函数的引用 |
空间大小 | 编译时就可以确定空间大小 | 运行时才知道空间大小 |
大小限制 | 固定大小内存分配 | 不固定大小内存分配 |
JavaScript 中的引用
JavaScript 在栈中存储基础数据类型和引用,在堆中存储对象和函数。堆是一种无序的存储结构,因此需要在栈中存储指向对象和函数的引用。
参考资料
- Managing memory using stack and heap: all you need to know
- JavaScript queue, stack, heap, thread, process, recursion, stack overflow, event loop, macro task, micro task, setTimeout(), nodeJS process.nextTick() — ALL explained in an UNDERSTANDABLE way!
- Understanding JavaScript — Heap, Stack, Event-loops and Callback Queue
- JavaScript Event Loop And Call Stack Explained
- JavaScript's Memory Management Explained