当前位置: 首页 > news >正文

计算机内存中的栈和堆

一、堆栈的定义

程序运行时,内存会划分出不同区域,其中最重要的两块就是栈(Stack)堆(Heap)

1. 栈(Stack)

  • 结构:一种线性的、后进先出(LIFO)的数据结构。
  • 管理方式:由操作系统或 JavaScript 引擎自动分配和释放,无需开发者手动干预。比如函数调用时,局部变量入栈;函数执行完,整块栈帧直接弹出,内存瞬间回收。
  • 特点
    • 速度快,直接通过移动栈指针来分配。
    • 空间相对较小,连续存储。
    • 存储大小固定、生命周期可预知的数据。

2. 堆(Heap)

  • 结构:更像一个杂乱但自由的大仓库,存储区域不一定连续,通过指针引用。
  • 管理方式动态分配。何时分配、何时释放并不严格跟随函数进出,而是由垃圾回收器(GC)通过算法判断对象是否还被使用,来决定回收时机。
  • 特点
    • 速度较慢,涉及内存查找与 GC。
    • 空间大,适合存放大小不定或需要长期存在的数据。

打个比方:栈像便捷的随身口袋,放快取快,但容量小;堆像家里的储物间,空间大但找东西(及收拾)要花时间。


二、JavaScript 的数据类型

JavaScript 的值分为两大阵营:

原始类型(Primitive)

  • undefined
  • null
  • boolean
  • number
  • bigint
  • string
  • symbol

它们的特点:不可变,大小相对固定(除了某些长字符串,但引擎有优化)。

对象类型(Reference / Object)

  • ObjectArrayFunctionDateRegExpMapSet等。
  • 特点:可变,结构复杂,大小动态增减

三、存储地方:栈与堆的“分工”

1. 基本数据类型的存储

绝大多数情况下,原始类型的值直接存在栈中。

  • 变量声明时,引擎会在栈中划分一块区域,把值直接放进去(比如数字10,布尔true)。
  • 栈变量本身持有这个原始值,不经过任何中间地址。

⚠️ 有一些“特殊”的原始值,如较长的字符串,引擎内部可能会把它们放进堆,而在栈上只存一个引用。这属于引擎优化,但从逻辑语义上,我们仍把字符串当作原始类型,赋值时依然会复制,行为上等同于直接存值

2. 对象数据类型的存储

对象的数据实体始终存放在堆内存中,而栈中只存储一个“门牌号”——即堆内存的引用地址。

  • 当你写let obj = { name: 'Alice' };,引擎会做两件事:
    1. 在堆中分配一块内存存放对象{ name: 'Alice' },得到一个地址(比如0x003FFF)。
    2. 在栈中给变量obj分配空间,里面存的值正是这个地址0x003FFF

访问obj.name时,先通过栈里的地址找到堆中的对象,再取出其属性。

这种分工的原因在于:对象大小可能在运行时随时变化(增减属性),把这种不稳定的数据放在容量有限、空间连续的栈里很危险。而栈只需保存一个固定大小的内存地址即可。


四、存储方式:按值 vs 按引用

这是区分原始类型和对象类型最核心的行为差异。

1. 原始类型 —— 按值存储和复制

操作直接对“值”本身进行,互不影响。

leta=10;letb=a;// 把 a 的值 10 复制一份给 bb=20;console.log(a);// 10,a 不变

a 和 b 在栈中有各自独立的空间,改一个不会影响另一个。

2. 对象类型 —— 按引用存储和复制

变量保存的是“引用地址”,复制时只复制地址,而不在堆里复制整个对象。

letobj1={name:'Alice'};letobj2=obj1;// 复制的是地址,obj2 也指向堆里同一个对象obj2.name='Bob';console.log(obj1.name);// 'Bob',obj1 跟着变了

obj1 和 obj2 里的地址相同,因此通过任何一个变量修改对象,都会反映在另一个上。

函数的参数传递也遵守同样规则:

  • 传原始类型:函数内部修改形参不会影响外部实参。
  • 传对象:修改对象属性会影响外部,因为内外指向同一个对象。
functionchange(num,obj){num=100;// 改的是局部副本obj.name='Zoe';// 改的是堆里的同一对象}letn=1;leto={name:'Tom'};change(n,o);console.log(n);// 1,未变console.log(o.name);// 'Zoe',变了

五、为什么要这样设计——深度理解

  1. 性能与效率
    栈分配只需移动指针,极快。原始类型大小已知、占用固定,适合栈。对象如果直接放在栈中,其动态扩展会引起大量内存搬移;放在堆中,栈上只保留一个指针,保持高效。

  2. 生命周期管理
    局部变量一般随函数退出销毁,栈自动弹出。对象却可能被多个变量引用、逃逸出当前作用域,堆配合垃圾回收能处理复杂存活分析。

  3. 内存布局与安全性
    栈连续、有序,容易产生栈溢出;堆则分散。把不确定性大的对象放堆,也让栈维持轻量安全。


六、进阶:那些“纯粹”之外的存储情况

实际引擎(如 V8)会优化存储,比如:

  • 小整数(Smi):可能直接编码在指针里,避免额外分配。
  • 字符串:字符串常量池,可能会在堆中存储,但逻辑上仍是不可变的原始类型。复制字符串时,通常表现为复制引用(写时复制),但对开发者透明,行为仍符合“按值传递”。
  • 闭包引用的变量:如果函数引用了外部原始类型变量,这个变量会被移到堆中(放在“环境”对象里),从而延长生命周期。这时原始值确实存在了堆里,但从语言视角它还是“原始值”,只是存在位置变成了堆。

这些实现细节不影响我们理解的大原则:原始类型表现为“值语义”,对象类型表现为“引用语义”;栈负责快速管理大小固定的值或地址,堆负责承载复杂动态的数据实体。


七、总结

  • 堆栈定义:栈是自动分配释放、有序快速的小容量区域;堆是动态分配、靠 GC 回收的大容量区域。
  • 存储地方:基本数据类型直接存于栈(值本身);对象实体存于堆,栈里只留堆地址。
  • 存储方式:基本类型按值复制,对象类型按引用复制。
  • 设计意图:兼顾性能与灵活性,让小而短命的数据速生速灭,大而长命的数据由堆和垃圾回收精细管理。

理解这一模型后,JavaScript 里赋值、传参、比较(===对对象比较地址)等常见行为就都有了坚实的底层基础。

http://www.jsqmd.com/news/973098/

相关文章:

  • 2026年众智商学院PMP报名材料加微信怎么准备?官网400冯老师PMI英文申请咨询 - 众智商学院职业教育
  • 不止OBD4:通过SE16N查T077S表,深入理解SAP总账科目组的字段状态控制逻辑
  • 【钢铁雄心4】超简单低延迟保姆级联机教程,一分钟学会钢铁雄心局域网联机!!
  • Scikit-image图像处理实战:从蒙娜丽莎解构到医学级滤波
  • 别再浪费频谱了!用USRP X410和正交上变频,手把手教你搭建高效射频发射链路
  • 别再混淆了!用PyTorch的ConvTranspose2d手把手搞懂反卷积(附代码验证)
  • 国内优质的静音发电机企业口碑推荐,附近发电机/高压发电机租赁/应急发电机/本地发电机出租,静音发电机品牌哪家强 - 品牌推荐师
  • VSCode + Ollama + Continue 本地 AI 代码助手 实操手册
  • ROS中使用命令行实现topic和service 通信
  • VS Code + AWS SSM零配置远程开发实战
  • Azure SDK for Python:微软云服务的 Python 入口
  • LLM把程序员的活干完了?我看完那篇HN热帖蚌埠住了
  • 哪家韩国留学机构专业?2026年6月推荐TOP5评测性价比高案例适用场景 - 品牌推荐
  • Agent学习01
  • 手把手教你用HTML+CSS复刻一个简约风个人主页(附完整源码和素材)
  • 深度实操指南:mattpocock/skills 从安装、核心技能到职场全场景落地
  • 2026年珠海跨境物流SCMP模块费用和试听课怎么确认?众智商学院冯老师资料 - 众智商学院职业教育
  • 2026年最新邢台市黄金回收店铺TOP5排行榜 黄金+白银+铂金+K金回收门店指南及联系方式电话推荐 - 大熊猫898989
  • 第3章 Agent 类型分类与设计模式
  • 2026年6月郑州黄金回收店推荐:五大专业评测报价透明防压价案例 - 品牌推荐
  • Matlab大气湍流相位屏生成工具:Zernike建模+波前仿真+斯特雷尔比评估
  • 深入AVB签名验证:从libavb源码看RSA验签与哈希比对的完整流程
  • 从监控服务器到第一个被监控设备:Zabbix 5.0安装后的快速上手指南
  • Claude 3.5归零层解析:语义保真度校验环的架构级移除
  • 大模型工程化跃迁:OpenAI 4.1、grok-3与Scaling Laws实战指南
  • Wine Quality 可复现机器学习实验:随机森林二分类实战
  • MySQL 学习笔记(第五期):用户管理与权限控制
  • Flutter Android 打包完全指南
  • 第【6】期--基于凸优化的多UAV-ISAC系统联合位置部署和功率分配研究-maltab完整代码+报告
  • 2026年华为云OpenClaw/Hermes Agent配置Token Plan集成保姆攻略