不管什么样的编程语言,在其代码执行的过程中都是需要为其分配内存的。但是不同的编程语言对内存的申请和释放会有不同的实现,主要分为手动和自动管理内存
- 手动管理内存:像C、C++等一些接近底层的编程语言,都是需要手动来申请和释放内存。
- 自动管理内存:像Java、JavaScript、Python等一些高级编程语言,都是自动帮助我们管理内存的。
内存生命周期
不管什么样的编程语言,以及它用什么方式来管理内存,其内存的管理都具备以下的生命周期:
- 分配内存:分配其需要的内存。
- 使用内存:使用分配的内存。
- 释放内存:使用完毕后,对其进行释放。
在 JavaScript 中,
- 当我们创建变量、函数或任何你能想到的东西时(对象),JS 引擎会为此分配内存并在不再需要时释放它。
- 分配内存是在内存中保留空间的过程,而释放则释放空间,准备用于其他目的。
- 每次我们分配一个变量或创建一个函数时,它的内存总是经历以下相同的阶段
- 分配内存 JavaScript 为我们解决了这个问题:它为我们创建的对象分配了我们需要的内存。
- 使用内存 使用内存是我们在代码中明确执行的操作:读取和写入内存只不过是从变量读取或写入变量。
- 释放内存 此步骤也由 JavaScript 引擎处理。一旦分配的内存被释放,它就可以用于新的目的。
内存管理上下文中的“对象”不仅包括 JS 对象,还包括函数和函数作用域。
内存空间
-
栈内存(stack):
是一块连续的内存区域,每个区块按照一定次序存放(后进先出)
所有原始数据类型都存储在栈内存中
-
堆内存(heap):
- 是不连续的内存区域,即数据可以任意存放, 主要存放的是对象等。
- 引用数据类型会在堆内存中开辟一个空间,并且会有一个十六进制的内存地址,在栈内存中声明的变量的值就是十六进制的内存地址。
- 函数也是引用数据类型,我们定义一个函数的时候,会在堆内存中开辟空间,会以字符串的形式存储到堆内存中去。
JavaScript 中所有变量首先指向堆栈。如果它是非原始值,则堆栈包含对堆中对象的引用。举个栗子
const name = 'curry' // 为字符串分配内存 const age = 30 // 为数字分配内存 const info = { // 这会在堆中创建一个新对象,并在堆栈中创建对它的引用。 name: 'kobe', age: 24 }
为什么要区分栈、堆
变量主要是两种形式
- 一种内容短小(比如一个int整数),需要频繁访问,但是生命周期很短,通常只在一个方法内存活
- 一种内容可能很多,可能不需要太频繁的访问,但生命周期较长,通常很多个方法中可能都要用到
那么自然将这两类变量分开就显得比较理性。
-
一类存储在栈区,通常是局部变量、操作符栈、函数参数传递和返回值
栈区就像临时工,干完就跑,所以超快,
缺点也很多,比如生命周期短,一般只能在一个方法内存活,通常最大栈区可用内存都很小,你不可能往栈区里堆很多数据。
-
一类存储在堆区,通常是较大的结构体(或者OOP中的对象)、需要反复访问的全局变量。
堆区就是各种慢,申请内存慢,访问慢,修改慢,释放慢,整理慢(或者说GC垃圾回收)
优点也不言而喻,访问随机灵活,空间超大,在不超可用内存的情况下你要多大就给多大。
栈 | 堆 |
---|---|
静态内存分配,故空间小 | 动态内存分配 ,故空间大 |
连续的内存区域 | 不连续的内存区域: |
反应快 | 反应慢 |
内存分配
JavaScript是自动管理内存的,所以在我们编写JS代码定义变量时就会为其分配内存。
根据JavaScript不同的数据类型,会对其分配到不同的内存空间中,数据类型主要分为基本数据类型和复杂数据类型:
-
对于基本数据类型的内存分配会在执行时,直接在栈空间中进行分配。
基本数据类型(也称值类型):
string、number、boolean、undefined、null、symbol
; -
对于复杂数据类型的内存分配会在堆内存中开辟一块空间,变量引用其内存地址
复杂数据类型(也称引用类型):
object、function、array
;
JS的数组的内存
传统语言数组的概念
像 C/C++ 这种传统的编译型的语言,它们的数组在内存中用一串连续的区域来存放一些值,而且它们的数组中存放的数据类型都需要预先设定成同一类型
JS数组
JS数组中存储的数据类型是可以不一样的;意味着,JS 数组中内存地址不是连续的。
因为传统语言数组下标取值,就是因为是连续,且每小块大小都相等的内存空间,可以直接对应上内存的地址。
而 JS 数组可以存放不同类型的数据,但它也能进行数组下标取值。这其实因为采用的是哈希映射的方式,获取到对应数组下标的值的。
不过,现在的 JS 引擎为了优化 JS 的性能,它会分配一个连续的内存空间给存储了相同数据类型的数组,以达到更好的遍历效果。所以,只要你数组里存的是相同类型的值,在内存中的地址还是连续的。
知识支撑
静态/动态内存
-
静态内存: 为这些值分配了固定数量的内存,所以原始值的大小是有限制的
-
动态内存: 引擎不会分配固定数量的内存。相反,将根据需要分配更多空间。
最后一句
学习心得!若有不正,还望斧正。