你需要知道的JavaScript内存空间知识

我穿越了,文章写于2019-11-24。

前言

" 相信接触过Java、Python等后端语言的同学来说,内存空间是一个老生常谈的话题,但是作为前端开发的同学来说,这个并不会被经常提及,并且在日常编码中并不会注意一些细节问题。比如面试中常会问到的深拷贝与浅拷贝、按值传递和按引用传递等,如果从内存空间的角度去理解,会发现对你JS又有了更深的理解。 "

01 内存生命周期

在JS中,一般可以将内存分为两种:栈(包含池)、堆。其声明周期可以大概分为三个阶段:

  • 内存分配(声明)
  • 内存读写(使用)
  • 内存回收(销毁)

02 栈内存与基础数据类型

JS基础数据类型:Number、String、Boolean、Null、undefined、symbol、bigInt(自行了解)。

以上这些值都有固定大小,一般都保存在栈内存中,由系统分配固定的内存空间大小。我们在操作的时候直接操作内存中的值,即也就是在传递中是按值传递,遵循后进先出的原则进行读取。

需要强调的是,JS在执行过程中执行流进入一个函数时,会生成一个当前函数的执行环境(EC),并且推入到栈内存中,即我们所说的环境栈。所以JS在执行过程中消耗的是栈内存。

03 堆内存与引用数据类型

JS引用数据类型:Object、Array、Date、RegExp等。

引用数据类型的值时保存在堆内存中的对象,其内存空间大小是动态分配的。需要注意的是,JavaScript中不能直接访问堆内存中的位置,即不能直接操作对内存对象。而我们在平时操作引用数据类型的时候,其实操作的是这个对象的内存地址。相对应的,这个地址会被保存在栈内存中,形成一个映射关系。

举个例子:

js 复制代码
var a = { b: 1 }; 
var c = 100; 
function fn(a1, c1) { 
    a1.b = 1000; 
    a1 = null; 
    c1 = 200; 
} 
fn(a, c); 
console.log(a); 
console.log(c);

这是一道简单的题目,但是很好的表达了上面的堆栈原理。

答案是:{b: 1000}和100

当传递a的时候,实际上传递的是当前a对象的引用(地址)给了a1,其存储在栈内存中,执行a1.b = 1000进行修改的时,会通过这个地址去操作堆内存的对象,将b的值改为1000;接着a1 赋值为null,那么这时候a1就不会再指向堆内存,但是a的引用还是存在,所以对象变为修改后的{b: 1000},这就是所谓的按引用传递

而当传递实参c给形参c1的过程中,会把100直接复制新的一份给了c1,此时修改c1200后,实际上操作的就是c1这个变量,而不会影响原来的c,即该过程是按值传递。

04 内存回收

JavaScript中,自带有垃圾回收机制。其工作原理是会在每个固定时间执行一次内存释放操作,它内部有一套具体的回收机制,通过这个机制去找那些不再使用的值,回收对应内存。

标记清除法

这个是目前JavaScript最常用的垃圾收集方式。

请看下面代码

js 复制代码
var a = 100;
console.log(a + 10086);
a = null;

可以理解为当JS执行流进入这个环境的时候,会首先将a标记为"进入环境",当a离开环境时(a = null),则将其标记为"离开环境"。在垃圾收集器运行时,回收标记为"离开环境"的变量,释放内存。

引用计数法

这个是早期Netscape浏览器下一种不太常见的垃圾收集策略,由于这种方式不能回收循环引用的变量,导致对应内存不能被及时回收。后面放弃了这种方式,转而采用了标记清除来实现。

引用计数算法定义"内存不再使用"的标准很简单,就是看一个变量的引用次数是否为0。如果为0,说明该变量已经不再需要了。

综合以上,我们在日常开发中需要注意当变量不需要再使用的时候,请将其内存及时归还(赋值为null),特别是全局变量、定时器、DOM节点、闭包等等。

相关推荐
是一碗螺丝粉4 分钟前
React Native 运行时深度解析
前端·react native·react.js
Jing_Rainbow5 分钟前
【前端三剑客-9 /Lesson17(2025-11-01)】CSS 盒子模型详解:从标准盒模型到怪异(IE)盒模型📦
前端·css·前端框架
爱泡脚的鸡腿9 分钟前
uni-app D6 实战(小兔鲜)
前端·vue.js
青年优品前端团队11 分钟前
🚀 不仅是工具库,更是国内前端开发的“瑞士军刀” —— @qnvip/core
前端
骑自行车的码农13 分钟前
🍂 React DOM树的构建原理和算法
javascript·算法·react.js
北极糊的狐19 分钟前
Vue3 中父子组件传参是组件通信的核心场景,需遵循「父传子靠 Props,子传父靠自定义事件」的原则,以下是资料总结
前端·javascript·vue.js
看到我请叫我铁锤1 小时前
vue3中THINGJS初始化步骤
前端·javascript·vue.js·3d
q***25211 小时前
SpringMVC 请求参数接收
前端·javascript·算法
Dream it possible!1 小时前
LeetCode 面试经典 150_图_克隆图(90_133_C++_中等)(深度优先:DFS)
c++·leetcode·面试·
q***33371 小时前
Spring Boot项目接收前端参数的11种方式
前端·spring boot·后端