developer.mozilla.org/zh-CN/docs/…
developer.mozilla.org/zh-CN/docs/…
JS中的基础数据类型,这些值都有固定的大小,往往都保存在栈内存中(闭包除外),由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按值访问数据在栈内存中的存储与使用方式类似于数据结构中的堆栈数据结构
- 引用数据类型 无固定值 存在堆内存(heap)
Object、Array、Date、RegExp、Function 等。
与其他语言不同,JS的引用数据类型,比如数组Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在变量对象中的一个地址,该地址与堆内存的实际值相关联。
内存生命周期
- 分配内存: 内存被操作系统分配,允许程序使用它 (当申明变量、函数、对象的时候,系统会自动为他们分配内存)
- 使用内存:通过在代码操作变量对内在进行读和写 (也就是使用变量、函数等)
- 释放内存:不用的时候,就可以释放内存,以便重新分配 (由垃圾回收机制自动回收不再使用的内存)
数据类型
- 基本数据类型
-
Undefined
-
Null
-
Boolean
-
String
-
Number
-
Symbol
-
BigInt
-
- 引用数据类型
- Objerct
- Json
- Array
- Function
- Map
- Weak Map
- Set
- Weak Set
- Objerct
在内存当中,基本数据类型存放在栈中,引用数据类型存放在堆中。说到这里就要说一下内存空间了,一般来说,js的内存空间分为栈(stack)、堆(heap)、池(一般也会归类栈中)。其中栈存放变量,堆存放复杂对象,池存放常量,所以也叫常量池。
堆 (heap)
存放复杂对象
栈 (stack)
存放变量
池 (pool)
存放常量
垃圾回收
JavaScript会在创建变量(对象、字符串)时自动分配内存,并在这些变量不被使用时自动释放内存,这个过程被称为垃圾回收。
在js中有垃圾回收机制,其作用是回收过期无效的变量,以防止内存泄漏。这些工作不需要我们去管理什么时候进行垃圾回收,js会自动进行,这让我们写起代码来感觉超级爽,哈哈。
下面来看一下js垃圾回收机制什么时候会回收变量。我们写代码的时候是区分全局变量和局部变量的,在此,我们看一下局部变量和全局变量的销毁。
- 局部变量:局部作用域中,当函数执行完毕,局部变量也就没有存在的必要了,因此垃圾收集器很容易做出判断并回收。
- 全局变量:全局变量什么时候需要自动释放内存空间则很难判断,所以在开发中尽量避免使用全局变量,以提高内存有效使用率
内存泄漏
内存泄漏可能对于前端开发着来说比较陌生,但是你肯定遇到过浏览器卡死的现象,卡死的原因就可能是因为一个死循环导致的内存爆满泄漏。所以对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。 对于不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak) 如果想模拟的话,可以按下面的步骤来进行操作:
- 打开开发者工具,选择 Memory
- 在右侧的Select profiling type字段里面勾选 timeline
- 点击左上角的录制按钮。
- 在页面上进行各种操作,模拟用户的使用情况。
- 一段时间后,点击左上角的 stop 按钮,面板上就会显示这段时间的内存占用情况。
垃圾回收算法
- 标记清除 标记清除算法将“不再使用的对象”定义为“无法到达的对象”。即从根部(在JS中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,保留。那些从根部出发无法触及到的对象被标记为不再使用,稍后进行回收。每一个变量都有自己的使用环境,当进入环境以后,垃圾回收机制就会给他打上一个“进入环境”的标签,从逻辑上来将,系统不能清除处于环境中的变量,因为只要是在环境中就有可能会使用到。当其离开环境时,会给其打上“离开环境”标签,这时候便可以进行回收了。
- 引用计数 现代浏览器基本上已经不再使用了,在这里我们做一下简单的介绍。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。简单来说就是看一个对象是否有指向它的引用。如果没有其他对象指向它了,说明该对象已经不再需要了。
Chrome 浏览器查看内存占用
按照以下步骤操作
- 打开Chrome浏览器开发者工具的Performance面板
- 选项栏中勾选Memory选项
- 点击左上角录制按钮(实心圆状按钮)
- 在页面上进行正常操作
- 一段时间后,点击Stop,观察面板上的数据
常见的JavaScript内存泄漏
- 意外的全局变量
- 被遗忘的定时器或者回调
- 闭包
- DOM外引用
参考链接
jinlong.github.io/2016/05/01/…
www.ruanyifeng.com/blog/2017/0…
垃圾回收策略
- 手动回收:c free()
- 自动回收:js 、 java、 python -> 垃圾回收器释放内存
栈回收:
ESP: 记录当前执行状态的指针
函数执行结束后,ESP 向下移动到下一个执行上下文中,这个过程就是栈销毁内存
堆回收
老生区:标记-清除、标记-整理
垃圾回收造成卡顿?
js 运行在主线程上,一旦执行垃圾回收,需要将目前正在执行的js 暂停,影响应用性能和响应性能,为了避免卡顿,实行增量标记算法