js 中的栈和堆

63 阅读3分钟

在javaScript中,栈(Stack)和堆(Heap)是用来管理程序运行过程中产生的数据和变量的两种不同的内存区域。它们各自扮演着不同角色,并且在内存管理和变量存储方面有着显著的区别:

栈 (Stack)

1. 特性:

  • 栈是一种线性数据结构,遵循后进先出(Last In,First Out,LIFO)原则。
  • 它由操作系统自动分配和释放,分配速度快,空间大小有限制,通常是固定的,比如在一些环境下,默认栈大小可能是几兆字节。
  • 栈内存分配效率高,因为它遵循固定大小和连续分配的原则。
  • 栈中的内存空间常用来存储:
    • 基本数据类型包括:undefinednullbooleannumberstringbigintsymbol
    • 函数调用时产生的执行上下文,包括局部变量、函数参数、返回地址等。

2. 生命周期:

  • 当一个函数调用时,相应的执行上下文会被压入栈顶,此时会为局部变量分配栈内存。
  • 当函数执行完毕或遇到return 语句时,其对应的上下文将从栈顶弹出,对应栈内存得到释放,变量也随之销毁。

堆(Heap)

1. 特性:

  • 堆内存是一个更加复杂的内存区域,不按照线性顺序分配内存,其内存地址空间是分散的,大小不固定,理论上可以动态增长至可用内存的最大值。
  • 堆内存由程序员通过构造函数(如new关键字创建对象实例)等方式动态分配,但并不由程序员直接释放,而是通过垃圾回收机制来管理。
  • 堆内存中存储的是复合数据类型,即引用类型的对象,如 ObjectArrayFunctionDate 等。

2. 生命周期

  • 当声明一个引用数据类型时,变量本身(也就是指针)存储在栈中,它指向堆中的实际对象。
  • 只要存在指向堆中对象的引用,对象就不会被垃圾回收器回收。当没有任何引用指向该对象时,垃圾回收器会在合适的时机回收该对象占用的堆内存。

3. 堆内存的操作

  • 创建新对象时,会在堆中分配内存,并返回指向该内存的引用。
  • 通过引用操作对象时,实际上是间接地操作堆中的内存。
  • 引用类型的赋值和传递实际上是复制指针,而非复制整个对象,因此两个变量可能指向同一个堆内存中的对象,这就是所谓的 “传址”。

总的来说,栈内存主要用于存储和管理生命周期受函数执行流程严格控制的基本类型和执行上下文信息,而堆内存则主要用于存储和管理生命周期不受函数执行流程限制的复杂对象。两者协同工作,共同支撑起js程序的内存管理。