目录


前言: 在JavaScript的生命周期中,对于内存的管理主要由三个步骤:内存分配、内存使用、内存释放。

一、内存分配

  1. 在定义变量时,就自动完成看内存的分配工作:
var a = 123;
var b = "javascript";
  1. 变量储存方式
    (1)对于数字、布尔值、null、字符串等这些简单的数据类型,将其储存在栈中
    (2)对于数组、对象等这些复杂数据类型,将变量储存在栈中,其对象内容储存在堆中,栈中的变量指针指向堆中其对象内容的的位置。

二、内存使用

使用内存过程实际上是对内存进行读取和写入的操作:

var a = 1;
console.log(a);// 读取内存中的值
a = 2;

三、内存释放

内存管理中问题最多的就是内存释放(垃圾回收),这一阶段的任务就是找到已经分配并且不再使用的内存,并对其内存空间进行释放。

1、垃圾回收?

垃圾回收:JavaScript代码运行时,需要分配内存空间来储存变量和值。当变量不在参与运行时,就需要系统收回被占用的内存空间,这就是垃圾回收。
回收机制

  • Javascript 具有自动垃圾回收机制,会定期对那些我们不再使用的变量、对象所占用的内存进行释放,原理就是找到不再使用的变量,然后释放掉其占用的内存。
  • JavaScript中存在两种变量:局部变量和全局变量。全局变量的生命周期会持续要页面卸载;而局部变量声明在函数中,它的生命周期从函数执行开始,直到函数执行结束,在这个过程中,局部变量会在堆或栈中存储它们的值,当函数执行结束后,这些局部变量不再被使用,它们所占有的空间就会被释放。
  • 不过,当局部变量被外部函数使用时,其中一种情况就是闭包,在函数执行结束后,函数外部的变量依然指向函数内部的局部变量,此时局部变量依然在被使用,所以不会回收。

2、垃圾回收实现方式

现在浏览器通常使用的垃圾回收方法有两种:标记清除,引用计数。

  1. 标记清除
  • 标记清除是浏览器常见的垃圾回收方式,当变量进入执行环境时,就标记这个变量“进入环境”,被标记为“进入环境”的变量是不能被回收的,因为他们正在被使用。当变量离开环境时,就会被标记为“离开环境”,被标记为“离开环境”的变量会被内存释放。
  • 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
  1. 引用计数
  • 另外一种垃圾回收机制就是引用计数,这个用的相对较少。引用计数就是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变为0时,说明这个变量已经没有价值,因此,在在机回收期下次再运行时,这个变量所占有的内存空间就会被释放出来。
  • 这种方法会引起循环引用的问题:

​obj1​​​和​​obj2​​​通过属性进行相互引用,两个对象的引用次数都是2。当使用循环计数时,由于函数执行完后,两个对象都离开作用域,函数执行结束,​​obj1​​​和​​obj2​​还将会继续存在,因此它们的引用次数永远不会是0,就会引起循环引用。

function fun() {
let obj1 = {};
let obj2 = {};

obj1.a = obj2; // obj1 引用 obj2
obj2.a = obj1; // obj2 引用 obj1
}

这种情况下,我们就要手动释放变量占用的内存:

.a =  null
obj2.a = null

3、减少垃圾回收

虽然浏览器可以进行垃圾自动回收,但是当代码比较复杂时,垃圾回收所带来的代价比较大,所以我们应该尽量减少垃圾回收。

  1. 对数组进行优化
    在清空一个数组时,最简单的方法就是给其赋值为[ ],但是与此同时会创建一个新的空对象,我们可以将数组的长度设置为0,以此来达到清空数组的目的。
  2. object进行优化
    对象尽量复用,对于不再使用的对象,就将其设置为null,尽快被回收。
  3. 对函数进行优化
    在循环中的函数表达式,如果可以复用,尽量放在函数的外面。