前言
大多数时候我们都不会关注这个问题,因为不论是内存分配还是垃圾回收,JavaScript引擎都会为我们处理,那JavaScript都是怎么处理的呢?下面就让我们详细的了解一下吧。
说垃圾回收前我们先了解一下什么是内存分配,JavaScript又是怎么分配内存空间的呢?由于内容较长,所以本文我们先详细了解一下内存分配吧。
内存分配
内存分配是指在创建变量、函数或者其他任何内容的时候,JS引擎会自动为我们分配内存,并且在不需要的时候释放内存。
每次我们创建一个变量或者创建一个函数时,该变量或函数的存储会经历以下三个阶段。
-
分配内存
在我们创建变量或函数的时候,JavaScript引擎会为我们分配一些内存空间来存放该变量的内容
-
使用内存
读取和写入内存无非就是变量读取和写入
-
释放内存
此步骤也由JavaScript引擎处理,使用完毕后,释放已分配的内存
了解了大致过程我们引入两个概念,分别是堆和栈。
内存堆和栈
目前我们知道,对于我们在JavaScript中定义的所有内容,JS引擎都会分配内存,并在不需要内存的时候将其释放。
那数据是怎么存储的呢?存储在哪里呢?
JavaScript引擎有两个地方可以存储数据,分别是栈(stack)和内存堆(memory heap)(堆和栈是引擎用于不同目的两个数据结构)。
1、静态内存分配(stack栈)
所有值都在栈中,因为它们都包含了原始值
栈是JavaScript用于存储静态数据的数据类型结构,静态数据是引擎在编译时知道大小的数据。在JavaScript中,这包括指向对象和函数的引用和原始值(strings, numbers, booleans, undefined 和 null);
由于JS引擎知道大小不会变,所以它们将为每个值分配固定大小的内存。
在执行之前立即分配内存的过程就叫 静态内存分配
因为JS引擎为这些值分配了固定大小的内存,所以原始值的大小是有限制的。这些值和整个堆栈的限制取决于浏览器。
当然 有静态内存分配就会有与之对应的动态内存分配
2、动态内存分配(Heap堆)
堆是用于存储数据的空间,JavaScript用于存储对象和函数。与栈不同,JS引擎不会为这些对象分配固定大小的内存空间。相反,将根据需要分配更多的内存空间。
这种方式分配内存也称为动态内存分配
两种内存分配的区别
静态内存分配(stack) | 动态内存分配(heap) |
---|---|
存放原始值和引用 | 存放对象和函数 |
大小编译时已知 | 大小编译时未知 |
下面我们来看一些例子:
const person = {
name: 'John',
age: 24,
};
复制代码
JS在堆中为此对象分配内存,然后将其引用存放在栈中。
const hobbies = ['hiking', 'reading'];
复制代码
数组也是对象,所以它们存储在堆中
let name = 'John'; // 为字符串分配内存
const age = 24; // 为数字分配内存
name = 'John Doe'; //为一个新的字符串分配内存
const firstName = name.slice(0,4); // 为一个新的字符串分配内存
复制代码
以上原始值都是不可变的,这意味着JavaScript不会更改原始值,而是创建一个新值,它们都存储在栈中。
注意: 所有变量首先指向栈。如果它是非原始值,则栈包含对堆中对象数据的引用。
堆的内存没有以任何特定的方式排序,这就是为什么我们需要在堆栈中保留对其的引用。你可以将引用视为地址,将堆中的对象视为这些地址所属的房屋。
从上图我们可以观察到如何存储不同的值。注意person和newPerson都是怎样指向同一个对象的。
const person = {
name: 'John',
age: 24,
};
首先会在堆里面存储person 的数据,然后在栈里面
存储数据的地址(引用)。
复制代码
如上面所说,在堆中创建一个新对象后,会在栈中创建对该对象的引用。
写在结尾
以上就是内存分配的所有啦,是不是感觉对JS的内存分配有了一定的了解呢?当然这是为后续的垃圾回收机制做铺垫,如有不对还请大家积极指出,我也会及时更正哒,感谢大家的认可,如果本文对你有帮助,就帮忙点个赞支持下吧,非常感谢。
参考
felixgerschau.com/javascript-…
developer.mozilla.org/zh-CN/docs/…