内存

由可读写单元组成,表示一片可操作空间

管理

人为地去操作一片空间的申请、使用和释放

管理流程

  1. 申请内存空间

    1. let obj = {};
  2. 使用内存空间

    1. obj.name = 'xx';
  3. 释放内存空间

    1. obj = null;

    垃圾

    JavaScript 中内存管理是自动的

  4. 对象不再被引用时是垃圾

  5. 对象不能从根上访问到时是垃圾

把垃圾占据的内存空间进行回收的过程就是垃圾回收

可达对象

  • 可以访问到的对象就是可达对象(引用、作用域链)
  • 可达的标准就是从根出嫁是否能够被找到
  • JavaScript 中的根就是可以理解为是全局变量对象(全局执行上下文)
    let obj = { name: 'xm' };
    let ali = obj;
    obj = null;
    
  1. obj 指向 { name: ‘xm’ } 的地址
  2. ali 指向 { name: ‘xm’ } 的地址
  3. obj 指为 null 空指针

但通过 ali 还是能访问到 { name: ‘xm’ } 的地址。所以 { name: ‘xm’ } 还是可达对象

function objGroup(obj1, obj2) {
    obj1.next = obj2;
  obj2.prev = obj1;

  return {
      o1: obj1,
    o2: obj2
  }
}

image.png
把 o1 通过 delete o1; 删除
image.png
把所有通往 o1 的连接都删除了,那么这部份就认为是垃圾。最终其空间会被 JavaScript 引擎所回收

常见 GC 算法

引用计数

  • 核心思想: 设置引用数,判断当前引用数是否为 0
  • 引用计数器
  • 引用关系改变时修改引用数字
  • 引用数字为 0 时立即回收

优点

  • 发现垃圾时立即回收
  • 最大限度减少程序暂停

缺点

  • 无法回收循环引用的对象
  • 时间开销大

    循环引用对象

    ```javascript function fn(){ const obj1 = {}; const obj2 = {};

    obj1.name = obj2; // 相互指针引用, 在引用计数中无法解决 obj2.name = obj1; }

fn(); ```

标记清除

  • 核心思想: 分标记和清除两个阶段完成
    • 遍历所有对象找标记活动对象
    • 遍历所有对象清除没有标记对象
  • 回收相应空间

image.png
优点

  • 可以解决对象循环引用问题

缺点

  • 回收时的地址不一定连续,会造成空间的碎片化,浪费空间
  • 不会阙发回收垃圾对象

image.png

标记整理

  • 标记清除的增强,以减少碎片化空间
  • 标记阶段的操作和标记清除一致
  • 清除阶段会先执行整理,移动活动对象移动到一侧的位置,再把活动对象的另一则进行空间回收

    分代回收

    V8 引擎