栈的内存空间是自动分配的,它由系统自动释放,堆的内存空间是动态分配的,大小不定,不会自动释放,需要 JS 引擎释放这些内存。v8 采用的分代式垃圾回收机制。

分代式垃圾回收机制

v8 堆内存结构包含新生代内存区,老生代内存区,大对象区,Map 区,代码区。垃圾回收发生在新生代内存区和老生代内存区。

从根(window,global)开始,找所有从根开始引用的对象,然后找这些对象引用的对象……,一直递归,被找到的对象就是活动对象,从根往下找不到的对象就是未活动对象,可以被回收。

新生代

存储空间小,垃圾回收频繁

  1. 新生代空间分为半个 From 空间,半个 To 空间
  2. 声明的对象首先分配到 From 空间。
  3. 垃圾回收时,复制 From 空间的活动对象到 To 空间。留在From空间的非活动对象会被自动回收
  4. 复制完成后,From 空间和 To 空间完成互换。To 空间变成新的 From 空间,From 空间变成新的 To 空间。

老生代

存储空间大,存放存活时间较久的对象

  1. 新生代的对象经过多次复制后依旧存活(至少经历过一次复制,且新生代 To 空间的内存占比超过了 25%),在下一次进行垃圾回收时,该对象直接转移到老生代中。
  2. 遍历堆中所有的对象,标记活动对象,清除未活动对象。
  3. 对象清除后,在整理的过程中,会将活动的对象往堆内存的一端进行移动。(碎片整理,方便存放较大的对象)
  4. 可以标记或者整理一部分对象,然后暂停,将执行权交给 js 主线程,待主线程空闲时再从原来标记的地方继续标记或者整理。(不影响主线程运行)
  5. 也可以利用增量标记、懒性清理、并发、并行来减少主线程挂起的时间。

小正
42 声望4 粉丝