目录

  • B站讲解视频地址
  • 栈内存和堆内存的区别与原理
    • 栈数据结构
    • 堆数据结构
    • 变量类型与内存的关系
      • 基本数据类型
      • 引用数据类型
      • 从内存角度来看变量复制
        • 基本数据类型的复制
        • 引用数据类型的复制
    • 栈内存和堆内存的优缺点
    • 栈内存和堆内存的垃圾回收
    • 闭包与堆内存

B站讲解视频地址

B站讲解视频地址

栈内存和堆内存的区别与原理

JS的内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)。
其中栈存放变量,堆存放复杂对象,池存放常量,所以也叫常量池。

栈数据结构

栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。
栈被称为是一种后入先出(LIFO,last-in-first-out)的数据结构。
由于栈具有后入先出的特点,所以任何不在栈顶的元素都无法访问。
为了得到栈底的元素,必须先拿掉上面的元素。

在这里,为方便理解,通过类比乒乓球盒子来分析栈的存取方式。

这种乒乓球的存放方式与栈中存取数据的方式如出一辙。 处于盒子中最顶层的乒乓球 5,它一定是最后被放进去,但可以最先被使用。 而我们想要使用底层的乒乓球 1,就必须将上面的 4 个乒乓球取出来,让乒乓球1处于盒子顶层。 这就是栈空间先进后出,后进先出的特点。

堆数据结构

堆是一种经过排序的树形数据结构,每个结点都有一个值。
通常我们所说的堆的数据结构,是指二叉堆。
堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。
由于堆的这个特性,常用来实现优先队列,堆的存取是随意,这就如同我们在图书馆的书架上取书,
虽然书的摆放是有顺序的,但是我们想取任意一本时不必像栈一样,先取出前面所有的书, 我们只需要关心书的名字。

变量类型与内存的关系

基本数据类型

Sting
Number
Boolean
null
undefined
Symbol

基本数据类型保存在栈内存中,因为基本数据类型占用空间小、大小固定,通过按值来访问,属于被频繁使用的数据。

为了更好的搞懂基本数据类型变量与栈内存,我们结合以下例子与图解进行理解:

let num1 = 1;
let num2 = 1;


PS: 需要注意的是闭包中的基本数据类型变量不保存在栈内存中,而是保存在堆内存中。

引用数据类型

Array,Function,Object...可以认为除了上文提到的基本数据类型以外,所有类型都是引用数据类型。
引用数据类型存储在堆内存中,因为引用数据类型占据空间大、大小不固定。
如果存储在栈中,将会影响程序运行的性能; 引用数据类型在栈中存储了指针,该指针指向堆中该实
体的起始地址。 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体

为了更好的搞懂变量对象与堆内存,我们结合以下例子与图解进行理解。

// 基本数据类型-栈内存
let a1 = 0;
// 基本数据类型-栈内存
let a2 = 'this is string';
// 基本数据类型-栈内存
let a3 = null;
// 对象的指针存放在栈内存中,指针指向的对象存放在堆内存中
let b = { m: 20 };
// 数组的指针存放在栈内存中,指针指向的数组存放在堆内存中
let c = [1, 2, 3];


因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从变量中获取了该对象的地址指针, 然后再从堆内存中取得我们需要的数据。

从内存角度来看变量复制

基本数据类型的复制

let a = 20;
let b = a;
b = 30;
console.log(a); // 此时a的值是多少,是30?还是20?  答案是:20

在这个例子中,a、b 都是基本类型,它们的值是存储在栈内存中的,a、b 分别有各自独立的栈空间, 所以修改了 b 的值以后,a 的值并不会发生变化。

从下图可以清晰的看到变量是如何复制并修改的。

引用数据类型的复制

let m = { a: 10, b: 20 };
let n = m;
n.a = 15;
console.log(m.a) //此时m.a的值是多少,是10?还是15?    答案是:15

在这个例子中,m、n都是引用类型,栈内存中存放地址指向堆内存中的对象, 引用类型的复制会为新的变量自动分配一个新的值保存在变量中, 但只是引用类型的一个地址指针而已,实际指向的是同一个对象, 所以修改 n.a 的值后,相应的 m.a 也就发生了改变。

从下图可以清晰的看到变量是如何复制并修改的。

栈内存和堆内存的优缺点

在JS中,基本数据类型变量大小固定,并且操作简单容易,所以把它们放入栈中存储。
引用类型变量大小不固定,所以把它们分配给堆中,让他们申请空间的时候自己确定大小,这样把它们分开存储能够使得程序运行起来占用的内存最小。
栈内存由于它的特点,所以它的系统效率较高。
堆内存需要分配空间和地址,还要把地址存到栈中,所以效率低于栈。

栈内存和堆内存的垃圾回收

栈内存中变量一般在它的当前执行环境结束就会被销毁被垃圾回收制回收, 而堆内存中的变量则不会,
因为不确定其他的地方是不是还有一些对它的引用。
堆内存中的变量只有在所有对它的引用都结束的时候才会被回收。

闭包与堆内存

闭包中的变量并不保存中栈内存中,而是保存在堆内存中。
这也就解释了函数调用之后之后为什么闭包还能引用到函数内的变量。

什么是闭包:

function A() {let a = 1;function B() {console.log(a);}return B;
}
let res = A();

函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。

函数 A 弹出调用栈后,函数 A 中的变量这时候是存储在堆上的,所以函数B依旧能引用到函数A中的变量。

现在的 JS 引擎可以通过逃逸分析辨别出哪些变量需要存储在堆上,哪些需要存储在栈上。

若对您有帮助,请点击跳转到B站一键三连哦!感谢支持!!!

栈内存和堆内存的区别与原理相关推荐

  1. 栈内存和堆内存的区别

    总结: 1 栈:为编译器自动分配和释放,如函数参数.局部变量.临时变量等等 2 堆:为成员分配和释放,由程序员自己申请.自己释放.否则发生内存泄露.典型为使用new申请的堆内容. 除了这两部分,还有一 ...

  2. 栈内存和堆内存的区别(一个笔试题的一部分)

    笔试题目:请解释一个栈内存与一个堆内存的区别,请分析下面代码运行是否有问题,如果有问题请改正. char* GetMemory(void) { char p[] = "Hello world ...

  3. 栈内存 ,堆内存区别 C++ 动态内存 == 与equal区别 复合函数奇偶性 三角函数转换公式: 虚函数和纯虚函数: C++ 中的运算符重载 数据封装,数据抽象 C++ 接口(抽象类

    目录 栈内存 ,堆内存区别 C++ 动态内存 == 与equal区别 复合函数奇偶性 三角函数转换公式: 虚函数和纯虚函数: C++ 中的运算符重载 数据封装,数据抽象 C++ 接口(抽象类): #和 ...

  4. 栈内存与堆内存的区别

    数据结构中的栈和堆 栈 :这是一种连续存储的数据结构,具有先进后出的性质.通常具有的操作有出栈.入栈(压栈)和取栈顶元素.想要读取栈中的某个元素,就必须将其之前所有的元素出栈才能完成. 堆:这是一种非 ...

  5. 栈内存和堆内存有什么区别?

    栈内存和堆内存有什么区别? 栈内存和堆内存是什么?有什么用? 栈内存.堆内存是什么? 栈内存和堆内存都是存储数据的地方. 为什么会分栈内存和堆内存?? 因为栈内存中存储的值的大小是固定的,堆内存中存储 ...

  6. java 堆内存和栈内存的区别_java中栈内存和堆内存有什么区别

    栈内存和堆内存的区别: 1.栈内存用来存放基本类型的变量和引用变量,堆内存用来存储java中的对象,无论是成员变量,局部变量,还是类变量,他们指向的对象都存储在堆内存中. (视频教程推荐:java视频 ...

  7. C++中栈内存和堆内存区别

    C++中栈内存和堆内存区别 栈内存:当对象** 所在的函数体**执行完毕时,栈内存里的数据就会被清理.如:Student std;(是栈内存) 堆内存:会一直存在,执行delete是会清楚.如果是指针 ...

  8. JavaScript栈内存和堆内存区别

    和栈这两个字我们已经接触多很多次,那么具体是什么存在栈中什么存在堆中呢?就拿JavaScript中的变量来说: 首先JavaScript中的变量分为基本类型和引用类型. 基本类型就是保存在栈内存中的简 ...

  9. 数据类型,栈内存、堆内存

    一.基础数据类型 二.栈和堆的区别 三.栈内存.堆内存 四.栈.队列.树.链表 基础数据类型 我把它总结为:USONB(是不是很nice哈哈) Undefined.String.Symbol.Obje ...

最新文章

  1. 学习Python编程开发可以从事的岗位有哪些?
  2. Github上这几个沙雕项目,够我玩三天!
  3. np.eye()的函数能将一个label数组,大小为(1,m)或者(m,1)的数组,转化成one-hot数组
  4. axios vue 加载效果动画_在vue中通过axios异步使用echarts
  5. 那些年困扰我们的Linux 的蠕虫、病毒和木马
  6. react启动命令_十分钟搭建React开发环境
  7. Java如何获得系统时间
  8. pdsh命令控制多台树莓派超爽
  9. 自旋锁 轻量锁_Java知识进阶-程序员升往架构师必经之路-自旋锁-知识铺
  10. Ubuntu下mysql跟换datadir,数据库存放路径,支持更改单个库的存放路径
  11. 充值核销卡密恶意并发请求防止重复利用卡密充值成功解决方案
  12. 阿里ACP考试题(只供参考)
  13. Spire.Doc 教程:如何将Word转换为PDF
  14. Mac 与PC键盘的对比及快捷键(黑苹果)
  15. 哈工大计算机科学与捄术学院,[哈尔滨工业大学]管理科学与工程
  16. Vue下使用docxtemplater-POI模式导出word
  17. dcs与plc与c语言的联系,PLC 与DCS的通讯方式,举例讲解
  18. 解决伪原创视频 改变视频md5原创
  19. 干货:明确数据分析目标的 3 个步骤,很多人还搞不清楚
  20. 浅谈Singularity容器

热门文章

  1. 软件工程 科学出版社 郑逢斌主编 第1章 软件工程概述 课后习题答案
  2. 探索式测试--第五章(混合探索式测试法)--读书笔记
  3. 番茄小说发布2022原创年度报告,入驻作者人数上涨300%,65%为90后作者
  4. 终结所有短信猫(GPRS,GSM,CDMA,PHS)的发短信问题,以及想语音告警的问题!
  5. 使用AntiXss.HtmlEncode方法来防止跨站点脚本攻击,后解码
  6. 法拉第是如何利用磁铁产生电流的呢?
  7. 事件之触摸及手势事件
  8. 2.建立场景图形-2叶节点(Geode)和几何信息
  9. 一句话说清OpenShift的核心价值!
  10. mysql表加锁与优化